java script lanjutan

95
Pengenalan Pengembangan web modern melibatkan sangat banyak bahasa pemrograman dan sistem. Pada sisi klien (front end) saja misalnya, secara standar kita memerlukan tiga bahasa pemrograman untuk membangun antarmuka aplikasi: HTML, CSS, dan Javascript. Masalah yang biasanya muncul ketika mengembangkan aplikasi seperti ini adalah manajemen file. Ketika mengembangkan aplikasi besar, ledakan jumlah file HTML, CSS, dan Javascript tidak dapat dihindari. Tidak cukup sampai di sana, berdasarkan best practice yang dikenal luas [1] , idealnya kita harus meminimalkan ukuran file dan menggabungkan masing-masing jenis file (Javascript dan CSS) menjadi 1 file saja. Kalau pada bahasa pemrograman lain terdapat compileratau build tools yang membantu kita melakukan hal ini, Javascript (maupun CSS dan HTML) tidak memiliki dukungan toolsserupa secara standar. Untungnya, para pengembang Javascript sendiri menyadari hal ini dan telah mengembangkan berbagai tools untuk membantu kita dalam melakukan manajemen file maupun hal-hal lainnya yang mempercepat pengembangan. Bagian ini akan membahas beberapa tools yang dapat digunakan untuk hal ini, beserta cara instalasi dan penggunaannya. NodeJS Sebelum mulai menggunakan tools yang diberikan, kita akan terlebih dahulu melakukan instalasi NodeJS . NodeJS adalah sebuah platform pengembangan perangkat lunak Javascript yang berjalan di luar browser. Sepintas NodeJS memiliki manfaat yang sama seperti Java Runtime Environment (JRE), yang merupakan tempat berjalannya aplikasi yang dibangun dengan bahasa pemrograman Java. Jika JRE dibutuhkan untuk menjalankan aplikasi Java, maka NodeJS dibutuhkan untuk menjalankan aplikasi Javascript yang dibangun untuk NodeJS. Langsung saja, berikut adalah langkah demi langkah instalasi NodeJS pada sistem operasi Windows: 1. Ambil perangkat lunak NodeJS dari website resminya di http://nodejs.org/ , melalui tombol install yang disediakan.

Upload: kind3rn

Post on 25-Dec-2015

89 views

Category:

Documents


2 download

DESCRIPTION

javascript lanjutan

TRANSCRIPT

Page 1: Java Script Lanjutan

Pengenalan

Pengembangan web modern melibatkan sangat banyak bahasa pemrograman dan

sistem. Pada sisi klien (front end) saja misalnya, secara standar kita

memerlukan tiga bahasa pemrograman untuk membangun antarmuka aplikasi: HTML,

CSS, dan Javascript. Masalah yang biasanya muncul ketika mengembangkan

aplikasi seperti ini adalah manajemen file. Ketika mengembangkan aplikasi

besar, ledakan jumlah file HTML, CSS, dan Javascript tidak dapat dihindari.

Tidak cukup sampai di sana, berdasarkan best practice yang dikenal luas [1],

idealnya kita harus meminimalkan ukuran file dan menggabungkan masing-masing

jenis file (Javascript dan CSS) menjadi 1 file saja. Kalau pada bahasa

pemrograman lain terdapat compileratau build tools yang membantu kita

melakukan hal ini, Javascript (maupun CSS dan HTML) tidak memiliki

dukungan toolsserupa secara standar.

Untungnya, para pengembang Javascript sendiri menyadari hal ini dan telah

mengembangkan berbagai tools untuk membantu kita dalam melakukan manajemen

file maupun hal-hal lainnya yang mempercepat pengembangan. Bagian ini akan

membahas beberapa tools yang dapat digunakan untuk hal ini, beserta cara

instalasi dan penggunaannya.

NodeJS

Sebelum mulai menggunakan tools yang diberikan, kita akan terlebih dahulu

melakukan instalasi NodeJS. NodeJS adalah sebuah platform pengembangan

perangkat lunak Javascript yang berjalan di luar browser. Sepintas NodeJS

memiliki manfaat yang sama seperti Java Runtime Environment (JRE), yang

merupakan tempat berjalannya aplikasi yang dibangun dengan bahasa pemrograman

Java. Jika JRE dibutuhkan untuk menjalankan aplikasi Java, maka NodeJS

dibutuhkan untuk menjalankan aplikasi Javascript yang dibangun untuk NodeJS.

Langsung saja, berikut adalah langkah demi langkah instalasi NodeJS pada

sistem operasi Windows:

1. Ambil perangkat lunak NodeJS dari website resminya

di http://nodejs.org/, melalui tombol install yang disediakan.

Page 2: Java Script Lanjutan

2. Jalankan installer yang baru didapatkan, untuk melihat tampilan seperti

gambar di bawah, dan tekan tombol “Next”.

Page 3: Java Script Lanjutan

3. Pastikan checkbox “I accept the terms in the Lincense Agreement” telah

di cek, kemudian tekan “Next”.

Page 4: Java Script Lanjutan

4. Tentukan lokasi instalasi (disarankan untuk tidak mengubah apa yang

disediakan sistem di sini), kemudian tekan “Next”.

5. Pada langkah selanjutnya, kita tidak perlu melakukan apa-apa, tetapi

pastikan bagian “Add to PATH” terpilih dengan benar (lihat bagian yang

diberi warna merah pada gambar). Tekan “Next”.

Page 5: Java Script Lanjutan

6. Tunggu proses instalasi hingga selsai.

Page 6: Java Script Lanjutan

7. Setelah proses selesai, tekan “Finish”.

8. Jalankan perintah node --version pada CMD. Jika NodeJS terpasang dengan

benar, sistem akan mengembalikan nomor versi.

Page 7: Java Script Lanjutan

Instalasi NodeJS juga menyertakan sebuah perangkat lunak lain,

yaitu npm. npm merupakan perangkat lunak manajemen paket, yang membantu kita

dalam melakukan instalasi library maupun perangkat lunak lain yang berjalan

di atas NodeJS. Berbagai perangkat lunak pendukung yang akan kita gunakan

nanti akan diinstalasi dengan menggunakan npm.

Build Tools

Build tools merupakan perangkat lunak yang membantu kita dalam melakukan

otomasi manajemen file. Biasanya kita hanya perlu memberitahukan kepada build

tools file mana yang ingin dikompilasi, dipindahkan, dan sejenisnya. Setelah

memberitahukan bagaimana manajemen file yang kita inginkan, kita cukup

memanggil build tools untuk menjalankan tugas-tugas tersebut secara otomatis.

Terdapat sangat banyak build tools pada platform NodeJS,

contohnya: GruntJS, Mimosa, Gulp, dan lainnya. Pada tulisan ini kita hanya

akan menggunakan Gulp saja, karena pembahasan akan keseluruhan build

tools tidak akan memungkinkan.

Instalasi Gulp dapat dilakukan dengan menjalankan perintah npm install gulp:

Page 8: Java Script Lanjutan

Untuk mempermudah dalam mempelajari penggunaan Gulp, kita akan melakukan

studi kasus. Misalkan kita sedang mengembangkan sebuah website sederhana

dengan struktur file seperti berikut:

Asumsikan kita ingin menggabungkan semua file Javascript yang ada dalam

direktori scripts serta file CSS yang ada dalam direktori styles menjadi

satu. File Javascript akan kita gabungkan menjadi file scripts.js dan

disimpan dalam direktori js. File CSS akan digabung menjadi

file styles.css dan disimpan dalam direktori css.

Untuk memberitahukan Gulp apa yang akan kita lakukan, kita harus membuat

sebuah file khusus yang dikenali Gulp terlebih dahulu. File ini harus

bernama gulpfile.js, dan harus diletakkan di direktori utama proyek. Dalam

kasus ini, kita harus membuat gulpfile.js di dalam direktori

tempat index.html berada. Isi dari gulpfile.js sangat sederhana, hanya

melakukan inisialisasi data:

Page 9: Java Script Lanjutan

1

2

3

4

5

var gulp = require('gulp');

gulp.task('default', function () {

// masukkan perintah gulp di sini

});

Terdapat lima perintah utama yang dapat kita berikan kepada Gulp, yaitu:

1. gulp.task(name, fn): yang telah kita gunakan pada kode di atas. Membuat

perintah baru untuk Gulp ketika dipanggil melalui command

line nantinya. Parameter name merupakan nama dari task yang dibuat,

sementara fnadalah fungsi yang dijalankan ketika task dipanggil.

2. gulp.run(tasks...): menjalankan satu atau lebih task yang dibuat

menggunakan gulp.task melalui kode (programmatically).

3. gulp.watch(glob, fn): melakukan eksekusi fungsi fn ketika file yang

dispesifikasikan oleh glob berubah isinya.

4. gulp.src(glob): membaca file yang memenuhi syarat sesuai

spesifikasi glob dan kemudian mengembalikan file tersebut satu per satu

untuk kemudian diproses.

5. gulp.dest(folder): file yang dikirimkan ke perintah ini akan disimpan

di dalam folder.

Selain kelima perintah di atas, Gulp menyediakan satu perintah pendukung

lagi, yaitu pipe(fn). Perintah pipemerupakan saluran penghubung antar dua

perintah, yang pada dasarnya memberikan fasilitas untuk menjalankan satu

perintah setelah perintah sebelumnya dijalankan.

Agar lebih mudah pahami, kita akan langsung melihat contoh penggunaan

beberapa perintah di atas. Sebagai langkah pertama, katakan lah kita akan

melakukan kopi seluruh file Javascript dari scripts ke js. Ganti isi

file glupfile.jsmenjadi seperti berikut:

1

2

3

4

5

6

7

var gulp = require('gulp');

var scriptFiles = './scripts/**/*.js';

gulp.task('default', function () {

gulp.src(scriptFiles)

Page 10: Java Script Lanjutan

8 .pipe(gulp.dest('./js/'));

});

Pada kode di atas, kita menggunakan perintah gulp.src dan gulp.dest secara

berurutan. Kedua perintah ini dihubungkan oleh pipe. Untuk melakukan

eksekusi task di atas, jalankan perintah glup dari command line.

Bagaimana jika kita ingin menggabungkan file atau meminimalkan file? Untuk

berbagai tugas tambahan seperti itu, kita dapat menggunakan tambahan perintah

dari pihak ketiga. Jalankan perintah berikut untuk memasang perintah baru

dari pihak ketiga:

1 $ npm install gulp-concat gulp-uglify

Perintah di atas melakukan instalasi terhadap dua perintah dari pihak

ketiga: gulp-concat untuk menggabungkan file, dan gulp-uglify untuk

meminimalkan kode. Cara penggunaannya juga sangat sederhana:

1

2var gulp = require('gulp');

Page 11: Java Script Lanjutan

3

4

5

6

7

8

9

10

11

12

var concat = require('gulp-concat');

var uglify = require('gulp-uglify');

var scriptFiles = './scripts/**/*.js';

gulp.task('default', function () {

gulp.src(scriptFiles)

.pipe(concat('scripts.js'))

.pipe(uglify())

.pipe(gulp.dest('./js/'));

});

Cukup gamblang dan sederhana. Kita hanya melakukan impor modul, dan kemudian

menggunakan modul tersebut (fungsiconcat() dan uglify()) melalui pipe.

Kesederhanaan ini merupakan daya tarik utama dari Gulp, sebagai sebuah build

tools yang sederhana sekaligus sangat bermanfaat. Penggabungan dan minifikasi

file CSS diserahkan kepada pembaca sebagai latihan.

Penguji HTTP Request

Ketika kita mengembangkan aplikasi web dinamis, seringkali kita akan

berhubungan dengan server. Hubungan dengan server ini biasanya dilakukan

secara dinamis, dengan menggunakan teknologi seperti XMLHttpRequest atau

WebSocket. Untuk memudahkan kita dalam menguji apakah server memberikan data

yang tepat atau sesuai dengan yang kita inginkan, kita dapat

menggunakan tools yang dapat mengirimkan permintaan ke server, dengan format

yang kita inginkan.

Beberapa tools yang dapat digunakan untuk kepentingan ini yaitu:

1. Advanced REST Client  (Chrome)

2. REST Client  (Firefox)

Kedua tools di atas cukup sederhana dan mudah digunakan. Kita hanya perlu

memasukkan URL yang akan kita uji, beserta dengan method HTTP-nya. Program

kemudian akan menampilkan data yang diberikan dari server, dan kita dapat

langsung memastikan apakah format yang diberikan sudah benar atau tidak. Hal

ini akan sangat memudahkan kita ketika ingin berbicara degnan server.

Page 12: Java Script Lanjutan

Catatan Kaki

XMLHttpRequest dan AJAX

Apa itu AJAX?

AJAX merupakan singkatan dari “Asynchronous Javascript and XML”. Secara

sederhana, AJAX memungkinkan kita untuk berkomunikasi dengan kode program

pada server melalui Javascript. Melalui AJAX, kita dapat memanggil kode pada

server melalui URL tertentu, dan menerima data / pesan hasil eksekusi oleh

server. Pada awal pengembangan, server mengembalikan data dalam format XML

(‘X’ pada AJAX). Pada prakteknya, server dapat mengembalikan data apapun,

selaam kode klien mengetahui format yang diberikan. Bahkan pada perkembangan

selanjutnya, format JSON menjadi lebih populer dibandingkan XML.

Bagian yang paling menarik dari AJAX ialah bahwa komunikasi dengan server

dilakukan secara asinkron (‘A’ pada AJAX). Hal ini berarti kita dapat

berkomunikasi dengan server tanpa mengganggu aktivitas atau eksekusi lain

pada sisi klien maupun server. Kita bahkan tidak perlu berpindah halaman atau

melakukan reload halaman untuk melihat hasil eksekusi kode AJAX.

Jadi, dengan AJAX kita dapat melakukan dua hal berikut:

1. Mengirimkan perintah kepada server tanpa harus berpindah

atau reload halaman.

2. Menerima data dari server dan kemudian mengolahnya. Data hanya akan

dapat diberikan server setelah kita mengirimkan perintah.

Setelah kita menerima dan mengolah data dari server, kita kemudian dapat

memperbaharui halaman sesuai dengan kebutuhan. Ingat juga bahwa komunikasi

ke server pada teknologi AJAX berjalan satu arah: kita mengirimkan perintah

ke server, dan hanya setelah itu server dapat mengirimkan data kembali ke

klien. Jika tidak ada pengiriman perintah dari klien, maka server tidak dapat

Page 13: Java Script Lanjutan

langsung memberikan data ke klien. Hal ini disebabkan oleh sifat dasar dari

web yang*stateless*, di mana server tidak menyimpan daftar klien yang sedang

terkoneksi dengannya. Tanpa server mengetahi siapa saja yang sedang

terkoneksi dengannya, maka ia tidak dapat mengirimkan data kepada klien

tersebut.

Keseluruhan fungsi dari AJAX ini dapat dicapai dengan menggunakan

objek XMLHttpRequest yang telah disediakan oleh browser. Langsung saja, kita

akan melihat bagaimana menggunakan objek ini.

Pembuatan XMLHttpRequest

Objek XMLHttpRequest (selanjutnya dirujuk sebagai xhr saja dalam kode dan

nama method) merupakan objek inti untuk melakukan operasi AJAX. Pembuatan

objek ini pada browser modern cukup mudah dan jelas:

1

2

3

4

5

6

var xhr;

if (window.XMLHttpRequest) {

xhr = new XMLHttpRequest();

} else {

alert("Browser tidak mendukung AJAX");

}

Sayangnya, kode di atas tidak dapat digunakan jika kita harus

mendukung browser lama seperti IE6. Jika ingin menggunakan operasi AJAX

pada browser lama, kita dapat menggunakan objek alternatif,

yaitu ActiveXObject:

1

2

3

4

5

6

7

8

var xhr;

if (window.XMLHttpRequest) { // Chrome, safari, IE7+, Opera, dll

xhr = new XMLHttpRequest();

} else if (window.ActiveXObject) { // IE5/6

xhr = new ActiveXObject("Microsoft.XMLHTTP");

} else {

alert("Browser tidak mendukung AJAX!");

}

Cara kedua yang mendukung browser lama ini tidak disarankan untuk digunakan,

karena dapat menambah beban pengujian. Anda lebih disarankan untuk

Page 14: Java Script Lanjutan

memperbaharui browser anda dibandingkan dengan menggunakan kode di atas.

Menggunakan browser lama yang tidak didukung lagi membuka celah kemanan yang

sangat besar, ditambah lagiActiveXObject merupakan objek yang tidak didukung

oleh standar Javascript secara resmi.

Mengirimkan Perintah ke Server

Mengirimkan perintah ke server dilakukan melalui protokol HTTP, yang dapat

dipanggil menggunakan method xhr.opendan xhr.send dari XMLHttpRequest:

1

2

xhr.open("GET", "http://example.com/ajax/", true);

xhr.send(null);

Method xhr.open digunakan untuk melakukan inisialisasi perintah yang akan

kita kirimkan ke server. Parameter yang kita kirimkan ke xhr.open memiliki

arti tersendiri:

Parameter pertama dari xhr.open menentukan HTTP Request Method yang

akan dikirimkan ke server. Terdapat total 9 method yang dapat

dikirimkan, tetapi yang paling umum digunakan adalah GET, POST, PUT,

dan DELETE. Ingat bahwa server juga harus dapat mengerti method yang

dikirimkan oleh klien. Nama method juga harus dituliskan dalam huruf

kapital.

Parameter kedua dari xhr.open berisi alamat URL server yang dapat

menerima dan mengerti perintah yang kita kirimkan. Untuk menjaga

keamanan, kita tidak dapat mengirimkan perintah ke domain yang berbeda

(misal: dari example.com ke contoh.com). Hal ini dibuat untuk

menghindari pencurian data pengguna ketika perantas berhasil menanamkan

kode Javascript mereka ke dalam halaman web kita. Jika memang perlu

mengirimkan perintah ke domain lain, baca HTTP Access Control (CORS)

Parameter ketiga dari xhr.open menentukan apakah perintah yang

dikirimkan bersifat asinkron atau tidak. Parameter ini bersifat

opsional, dan jika tidak diisi akan bernilai true. Dalam kebanyakan

kasus, parameter ini tidak perlu diisikan.

Setelah selesai melakukan inisialisasi melalui xhr.open, kita kemudian dapat

mengirimkan perintah ke server dengan menggunakan method xhr.send.

Method xhr.send menerima satu parameter yang bersifat opsional. Parameter ini

berisi data yang akan kita kirimkan ke server. Data yang dikirimkan dapat

disimpan dalam beberapa jenis objek,

yaituFormData, Blob, ArrayBufferView, Document, dan DOMString. Jika tidak

Page 15: Java Script Lanjutan

mengirimkan data ke server, kita dapat mengosongkan parameter ini, atau

mengisikannya dengan nilai null.

Untuk dapat mengirimkan data ke server, tentunya kita juga harus mengetahui

format pengiriman data yang dikenal oleh server pada HTML. Misalnya,

untuk method GET pada HTML, data dikirimkan secara otomatis melalui Query

String dalam format seperti berikut:

1 http://example.com/path?param1=value1&param2=value2...

Karena bentuk format data yang sederhana ini kita dapat langsung mengirimkan

data melalui URL pada server, pada method xhr.open seperti berikut:

1

2

xhr.open("GET", "http://example.com/path?param1=value1&param2=value2", true);

xhr.send(null);

Sayangnya, hal ini tidak dapat kita gunakan pada pengiriman data

menggunakan method POST. Jika ingin mengirimkan data menggunakan method POST,

kita harus terlebih dahulu menyimpan data yang ada di dalam objek yang dapat

diterima oleh xhr.send dan mengirimkannya melalui xhr.send. Berikut adalah

contoh penggunaan objek FormDatauntuk mengambil data dalam form dan

mengirimkannya melalui POST:

1

2

3

4

5

var form = document.querySelector("#form-login");

var formData = new FormData(form);

xhr.open("POST", "http://example.com/login");

xhr.send(formData);

Kita bahkan dapat menambahkan data baru ke FormData jika diperlukan (misalnya

untuk data yang tidak perlu diisikan oleh pengguna seperti nomor

pendaftaran). Kita dapat menggunakan method FormData.append untuk ini:

1

2

3

4

5

6

var form = document.querySelector("#form-daftar");

var formData = new FormData(form);

formData.append("NomorPendaftaran", noDaftar++);

Page 16: Java Script Lanjutan

7xhr.open("PSOT", "http://example.com/register");

xhr.send(formData);

Seperti yang dapat dilihat, FormData.append menerima dua buah parameter:

parameter pertama berisikan nama data yang dikirimkan, dan parameter kedua

berisi nilai (isi) dari datanya.

Menangani Respon Server

Setelah dapat mengirimkan data dan perintah ke server, langkah selanjutnya

dari pemrograman AJAX adalah menerima (dan menangani) respon dari server akan

perintah kita. Untuk dapat melakukan hal ini, kita harus membuat sebuah

fungsi baru dan mengikatkannya pada xhr.onreadystatechange, seperti berikut:

1

2

3

4

5

var fungsiRespon = function () {

// kode...

};

xhr.onreadystatechange = fungsiRespon;

Method xhr.onreadystatechange merupakan method yang dijalankan ketika

atribut xhr.readyState dari objekXMLHttpRequest berubah nilainya.

Atribut xhr.readyState menyimpan penanda status dari request yang kita

kirimkan ke server. Terdapat lima nilai xhr.readyState yang dimungkinkan,

yaitu:

Nilai State Deskripsi

0 UNSENT xhr.open belum dipanggil.

1 OPENED xhr.open telah dipanggil, tetapi xhr.send belum.

2 HEADERS_RECEIVED xhr.send telah dipanggil, dan server telah mengembalikan header dan status HTTP.

3 LOADING Sedang mengambil data respon dari server.

Page 17: Java Script Lanjutan

Nilai State Deskripsi

4 DONE Seluruh operasi telah selesai.

Karena kita ingin mengambil respon dari server, maka di

dalam fungsiRespon kita perlu melakukan cek status darixhr.readyState dan

kemudian melakukan sesuatu jika respon server sudah didapatkna (operasi sudah

selesai). Status dapat kita akses langsung seperti berikut:

1

2

3

4

5

var fungsiRespon = function () {

if (xhr.readystate === 4) {

// respon dari server sudah diterima

}

}

Setelah memastikan server memberikan respon sepenuhnya, kita lalu masih harus

memastikan server tidak mengembalikan pesan kesalahan. Status keberhasilan

atau kesalahan pada server HTTP dikomunikasikan kepada client melalui HTTP

Status Code. Contohnya, jika server sukses menjalankan perintah tanpa masalah

kita akan diberi kode 200. Jika halaman tidak ditemukan maka kita akan

diberikan status code 404. Dengan pengetahuan ini, kita dapat melakukan

pengecekan tambahan, untuk memastikan server menjalankan perintah dengan

benar. HTTP Status Code dapat diakses melalui xhr.status:

1

2

3

4

5

6

7

8

9

10

11

var fungsiRespon = function () {

if (xhr.readystate === 4) {

if (xhr.status === 200) {

// proses data

} else if (xhr.status === 404) {

alert("Lokasi URL tidak ditemukan pada server!");

} else if (xhr.status === 500) {

alert("Server error!");

}

}

}

Page 18: Java Script Lanjutan

Sampai titik ini kita sudah memastikan server mengembalikan data yang

lengkap, tanpa pesan kesalahan. Selanjutnya kita dapat langsung mengakses

data yang diberikan oleh server, untuk diolah lebih lanjut. Data yang

diberikan oleh server dapat diakses melalui dua buah properti khusus:

xhr.responseText - mengambil respon server dalam format String

xhr.responseXML - mengambil respon server dalam objek XMLDocument

Setelah mendapatkan data dalam format sesuai kebutuhan kita, kemudian kita

dapat mengolah data tersebut sesuai keinginan. Jika data kembalian yang

diberikan dibuat dalam format JSON, kita harus terlebih dahulu mengakses data

melalui xhr.responseText. Pembahasan lebih lanjut mengenai hal ini akan

dilakukan pada bagian berikutnya.

Note

Cara pengambilan respon yang dibahas pada bagian ini adalah cara pengambilan

respon untuk perintah asinkronus. Ketika menggunakan perintah sinkronus, kita

cukup memasukkan kode pengolahan data setelah xhr.send karena kode akan

berhenti dieksekusi sampai xhr.send selesai dijalankan.

Pengolahan Data JSON

Seperti yang telah dijelaskan pada awal tulisan, meskipun AJAX memiliki kata

XML di dalamnya, pada prakteknya kebanyakan pertukaran informasi dan data

pada aplikasi web modern dilakukan melalui JSON. JSON merupakan

formatnative dari Javascript, di mana format penulisan JSON sama persis

dengan format penulisan objek pada Javacsript (yang bahkan nampak dari

namanya: JavaScript Object Notation).

Untuk bekerja dengan JSON dalam Javascript, kita dapat menggunakan

objek JSON yang hanya memiliki

dua method:JSON.parse dan JSON.stringify. JSON.parse mengambil sebuah string

JSON dan menjadikannya objek Javascript, sementara JSON.stringify melakukan

hal sebaliknya: mengubah objek Javascript menjadi string JSON yang valid.

Untuk dapat lebih mudah memahami kegunaan dari kedua method ini, kita akan

langsung melihat contoh penggunaannya.

Membaca JSON Menjadi Objek

JSON.parse menerima dua buah parameter, dengan parameter pertama berupa

string yang akan diubah menjadi objek dan parameter kedua yang bersifat

opsional:

Page 19: Java Script Lanjutan

1

2

3

4

5

var response = "{\"health\": 3000, \"mana\": 400, \"str\": 86, \"agi\": 63, \"int\": 66}"

var ResObj = JSON.parse(response);

ResObj["health"]; // 3000

ResObj.mana; // 400

Parameter kedua dari JSON.parse dapat kita gunakan untuk melakukan sesuatu

terhadap data pada string, sebelum data tersebut dimasukkan ke dalam objek.

Parameter kedua ini menerima sebuah fungsi dengan dua parameter yang masing-

masing adalah nama atribut dan nilai atribut dari string JSON yang sedang

dibaca. Fungsi akan dijalankan terhadap semua atribut JSON yang ada, sehingga

kita dapat mengubah nilai dari atribut jika diinginkan. Nama umum dari

parameter kedua ini adalah reviver. Perhatikan kode berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

var reviver = function (k, v) {

console.log(k + ": " + v);

};

var data = '{"satu": 1, "dua": 2, "tiga": {"empat": 4, "lima": 5}}';

JSON.parse(data, reviver);

// Keluaran:

// satu: 1

// dua: 2

// empat: 4

// lima: 5

// tiga: [object Object]

// : [object Object]

Beberapa hal yang dapat kita pelajari dari kode di atas:

Fungsi revivier dijalankan ke masing-masing atribut JSON secara

berurutan (“satu”, “dua”, “tiga”).

Ketika menemukan atribut yang memiliki nilai objek (JSON)

lain, reviver terlebih dahulu diterapkan pada atribut objek yang di

Page 20: Java Script Lanjutan

dalam (pada contoh kita: “empat” dan “lima” tercetak terlebih dahulu

sebelum “tiga”).

Terdapat satu atribut tambahan yang tidak ada dalam data, yaitu cetakan

terakhir (: [object: Object]). Atribut ini mewakili keseluruhan JSON

yang kita kirimkan, dan akan selalu dibaca paling terkhir. Hal ini

dibuat agar kita juga dapat mengubah objek utama (misal:

menambahkan method) jika diperlukan. Kita tetap harus ingat untuk

menangani kasus ini bahkan ketika kita tidak mengubah objek utama,

biasanya dengan mengembalikan nilai awal (v pada kode di atas)

agar JSON.parse tidak mengembalikan undefined.

Untuk memperjelas masalah penanganan objek utama pada poin ketiga, perhatikan

kode berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

var kosong = JSON.parse(data, function (k, v) {

return v * 2;

});

var isi = JSON.parse(data, function (k, v) {

// if (k === "") return v;

if (k === "" || typeof v === "object") return v;

return v * 2;

});

kosong; // NaN

isi; // {"satu": 2, "dua": 4, "tiga": {"empat": 8, "lima": 10}}

Pada kode di atas, kita dapat melihat bagaimana jika kita tidak melakukan

pengecekan nilai k kosong maka objek hasil tidak akan dikembalikan. Sebagai

latihan, coba ganti baris if pada fungsi milik isi dengan yang dikomentari

dan lihat hasilnya. Kegunaan dari cek typeof v === "object diberikan sebagai

latihan kepada pembaca.

Memanfaatkan pengetahuan ini, kita dapat mengembangkan fungsi reviver yang

membuat objek penuh beserta denganmethod baru seperti berikut:

1

2var response = "{\"health\": 3000, \"mana\": 400, \"str\": 86, \"agi\": 63, \"int\": 66}"

Page 21: Java Script Lanjutan

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

var reviver = function (k, v) {

if (k === "") {

v.getStr = function () {

return v.str;

}

return v;

}

return v * 2;

};

var TransformedObj = JSON.parse(response, reviver);

TransformedObj["health"]; // 6000

TransformedObj.mana; // 800

TransformedObj.getStr(); // 172

Selanjutnya, mari kita lihat bagaimana cara mengubah objek menjadi string

JSON.

Mengubah Objek Menjadi String

Selain menerima string JSON dan mengubahnya ke dalam objek Javascript,

seringkali kita juga perlu mengirimkan data baru ke server, yang berasal dari

objek Javascript. Untuk kasus ini kita memerlukan mekanisme untuk mengubah

objek menjadi string JSON. Javascript menyediakan method JSON.stringify untuk

melakukan hal ini. Penggunaan sederhanamethod ini sangat mudah:

1

2

3

4

5

6

7

var obj = {

model: "L925",

size: 3.5,

age: 18,

conn: "4G"

};

Page 22: Java Script Lanjutan

8

9

10

var jsonString = JSON.stringify(obj);

jsonString; // '{"model":"L925","size":3.5,"age":18,"conn":"4G"}'

Begitupun, JSON.stringify memiliki parameter kedua dan ketiga yang sifatnya

opsional namun cukup berguna. Parameter kedua dari JSON.stringify mirip

dengan parameter kedua dari JSON.parse, yaitu sebuah fungsi yang digunakan

untuk melakukan proses data dalam objek sebelum objek tersebut dijadikan

string. Berikut adalah contoh penggunaannya:

1

2

3

4

5

6

var filteredJSON = JSON.stringify(obj, function (k, v) {

if (typeof v === "string") return undefined;

return v;

});

filteredJSON; // '{"size":3.5,"age":18}'

Seperti yang dilihat di atas, fungsi yang dikirimkan diterapkan ke semua

atribut objek untuk kemudian diproses. Kita juga dapat mengisikan array pada

parameter kedua. Jika diisikan dengan array, isi dari array akan dianggap

menjadi atribut yang ingin kita masukkan dalam string JSON, seperti berikut:

1

2

3

var altJSON = JSON.stringify(obj, ["model", "conn"]);

altJSON; // '{"model":"L925","conn":"4G"}'

Parameter ketiga dari JSON.stringify digunakan untuk memperindah string JSON

hasil proses. Kita dapat mengirimkan string yang dijadikan sebagai spasi

pemisah pada string JSON yang dihasilkan. Jika parameter ketiga diisikan

angka, maka angka tersebut akan menjadi jumlah spasi yang dimasukkan pada

pemisah string JSON. Langsung saja, berikut contoh penggunaannya:

1

2

3

4

JSON.stringfiy(obj, ["model", "conn"], "\t");

// keluaran:

// "{

// "model": "L925",

Page 23: Java Script Lanjutan

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

// "conn": "4G"

// }"

JSON.stringfiy(obj, ["model", "conn"], "aaaa");

// keluaran:

// "{

// aaaa"model": "L925",

// aaaa"conn": "4G"

// }"

JSON.stringfiy(obj, ["model", "conn"], 4);

// keluaran:

// "{

// "model": "L925",

// "conn": "4G"

// }"

Page 24: Java Script Lanjutan

WebSocket

WebSocket merupakan sebuah protokol komunikasi dua arah yang dapat digunakan

oleh browser. Jika pada AJAX kita hanya dapat melakukan komunikasi satu arah

dengan mengirimkan request kepada server dan menunggu balasannya, maka

menggunakan WebSocket kita tidak hanya dapat mengirimkan request kepada

server, tetapi juga menerima data dari server tanpa harus

mengirimkan request terlebih dahulu. Hal ini berarti ketika menggunakan

WebSocket pengguna harus terus menerus terkoneksi dengan server, dan kita

memerlukan sebuah server khusus untuk dapat menjalankan aplikasi WebSocket

dengan benar. Sederhananya, perhatikan gambar berikut:

Page 25: Java Script Lanjutan

Dari gambar di atas, kita dapat melihat bagaimana dalam kasus AJAX, setiap

request dari pengguna maupun respon dari server dilakukan secara terpisah.

Jika ingin mengirimkan request ke server, kita perlu membuka koneksi baru

yang kemudian akan dibalas oleh server seperti ia membalas permintaan halaman

HTML biasa. Server juga tidak dapat langsung melakukan pengiriman data ke

klien tanpa ada permintaan terlebih dahulu. Hal ini berbeda dengan pola

komunikasi WebSocket, di mana koneksi berjalan tanpa terputus dan server

dapat mengirimkan data atau perintah tanpa harus ada permintaan dari pengguna

terlebih dahulu. Dengan begitu, WebSocket bahkan juga memungkinkan server

mengirimkan data atau perintah ke semua klien yang terkoneksi, misalkan untuk

memberikan notifikasi global.

Untuk dapat melihat langsung bagaimana cara kerja WebSocket, kita akan

langsung melakukan eksperimen. Objek yang diperlukan untuk menggunakan

WebSocket dari browser adalah WebSocket. Tetapi sebelumnya, kita memerlukan

sedikit persiapan terlebih dahulu, yaitu komponen server dari WebSocket.

Komponen Server WebSocket

Page 26: Java Script Lanjutan

Teknologi WebSocket membutuhkan cara penggunaan yang sama sekali berbeda

dibandingkan dengan AJAX. Jika pada AJAX kita dapat mengguankan komponen

server yang sama dengan server HTTP pada umumnya, untuk WebSocket kita

memerlukan komponen server khusus. Hal ini disebabkan oleh model komunikasi

WebSocket yang mengharuskan pengguna terkoneksi dengan server sepanjang

aplikasi masih digunakan. Arsitektur server yang diperlukan untuk melayani

banyak koneksi terbuka seperti ini tentu berbeda dengan arsitektur yang

dibutuhkan untuk koneksi satu arah seperti pada HTTP. Ketika menggunakan

WebSocket, biasanya kita akan memerlukan komponen server (beserta kode sisi

server) khusus.

Adapun beberapa contoh komponen server untuk WebSocket yaitu:

1. Socket.IO (Javascript)

2. SignalR (.Net)

3. Jetty (JVM)

4. Event Machine (Ruby)

5. Tornado (Python)

Bahasa yang disebutkan pada daftar di atas adalah bahasa yang digunakan pada

sisi server.

Persiapan Eksperimen WebSocket

Sebelum kita dapat mencoba menggunakan WebSocket, terlebih dahulu kita akan

perlu membangun komponen server yang dapat mengerti protokol WebSocket, dan

dapat mengerti pesan yang akan kita kirimkan kepada mereka. Untuk memudahkan

pembaca, sebuah komponen server khusus telah disiapkan. Silahkan

download sampel komponen server (websocket-sample) ini terlebih dahulu.

Terdapat dua buah server yang diberikan, yaitu:

1. index.js merupakan komponen yang dirancang sebagai server dari sistem

chatting sederhana.

2. zero.js merupakan komponen yang dirancang sebagai server sistem

menonton game (seperti twitch.tv) sederhana.

Kita akan membangun klien dari index.js dari awal, sementara klien

untuk zero.js akan dimodifikasi dari contoh permainan sederhana yang sudah

dipersiapkan sebelumnya. Silahkan download juga kode untuk permainan

serderhana tersebut, dan coba pelajari cara kerjanya.

Page 27: Java Script Lanjutan

Menjalankan server WebSocket dari kedua kode tersebut juga sangat mudah,

cukup eksekusi kode dengan NodeJS:

1

2

$ node index.js

$ node zero.js

Setelah memilki semua komponen dasar yang diperlukan, kita akan mulai

mempelajari WebSocket dengan menelaah objek WebSocket terlebih dahulu.

Membuat Objek WebSocket

Pembuatan objek WebSocket (selanjutnya dirujuk sebagai ws saja) sangat mudah.

Kita dapat langsung memanggilconstructor dari objek tanpa perlu melakukan

pengecekan tambahan. Berikut adalah contoh pembuatan objek WebSocket baru:

1 var ws = new WebSocket("ws://www.example.com/socketserver");

Dan kita telah membuat sebuah objek WebSocket, sekaligus mencoba melakukan

koneksi ke alamat yang diberikan padaconstructor. Constructor dari ws juga

memiliki parameter kedua yang bersifat opsional. Parameter kedua ini dapat

berupa sebuah string ataupun array dari string, yang berisi nama dari

subprotokol WebSocket yang akan kita gunakan. Subprotokol merupakan “pesan”

tambahan yang dapat kita kirimkan ke server agar server mendapatkan informasi

tambahan yang dibutuhkan untuk memberikan respon. Subprotokol ini dibuat oleh

pengembang sendiri, dan baik klien maupun server harus dapat mengerti

subprotokol yang dikirimkan. Kegunaan utama dari subprotokol adalah agar baik

klien maupun server dapat yakin bahwa lawan bicaranya benar-benar mengerti

pesan yang dikirimkan maupun diterima. Kita tidak ingin server Dota2 versi 1

berkomunikasi dengan klien Dota2 versi 2 misalnya.

Penambahan subprotokol pada constructor WebSocket tidak rumit sama sekali:

1

2

var ws1 = new WebSocket("ws://www.example.com/socketserver", "dota2v1");

var ws2 = new WebSocket("ws://www.example.com/socketserver", ["dota2v1", "dota2v2"]);

Ketika kita mengirimkan array sebagai parameter kedua, berarti kita

memberitahukan ke server bahwa klien yang dibangun dapat mengerti semua

protokol yang ada di dalam array tersebut. Begitupun, pada akhirnya server

lah yang menentukan protokol mana yang akan digunakan. Klien kemudian dapat

mengelola data atau perintah sesuai dengan protokol yang digunakan server.

Menanggapi Server WebSocket

Page 28: Java Script Lanjutan

Setelah membuka koneksi, tentunya kita ingin berinteraksi dengan server.

Pertama-tama, mari kita lihat terlebih dahulu bagaimana cara menangani

perintah maupun data yang diberikan oleh server kepada kita.

Terdapat empat method utama yang dapat kita gunakan untuk menangani data dan

perintah yang dikirimkan server:

1. ws.onerror, method yang dijalankan ketika terjadi kesalahan pada

koneksi dengan server. Bersifat opsional.

2. ws.onclose, method yang dijalankan ketika koneksi dengan server telah

ditutup. Bersifat opsional. Memiliki satu parameter, CloseEvent yang

menyimpan detil pesan kesalahan yang terjadi.

3. ws.onopen, method yang dijalankan pertama kali ketika telah tersambung

dengan server. Bersifat opsional.

4. ws.onmessage, method yang dijalankan ketika menerima pesan dari server.

Memiliki satu parameter yang berisiMessageEvent, sebuah

objek event yang juga menyimpan data berupa pesan dari server melalui

propertiMessageEvent.data.

Keempat method yang ada di atas dapat digunakan semuanya ataupun

hanya ws.onmessage saja. Karena model pemrograman yang bersifat *event

based*, kita cukup hanya menspesifikasikan fungsi yang dijalankan pada

setiap eventdi atas saja. Browser akan secara otomatis mengeksekusi kode

ketika event terjadi. Berikut adalah contoh penggunaan keempat fungsi di

atas:

1

2

3

4

5

6

7

8

9

10

11

12

13

var ws = new WebSocket("ws://www.example.com/socketserver");

ws.onopen = function() {

console.log("Koneksi berhasil!");

};

ws.onerror = function () {

console.log("Koneksi gagal.");

};

ws.onclose = function (event) {

console.log("Koneksi telah ditutup. Pesan penutupan: " + event.code);

Page 29: Java Script Lanjutan

14

15

16

17

18

19

};

ws.onmessage = function (message) {

var data = JSON.parse(message.data);

// lakukan sesuatu dengan data

};

Perhatikan bagaimana kita menggunakan JSON.parse untuk melakukan pembacaan

data pada ws.onmessage. Meskipun kita dapat menggunakan format lain seperti

XML atau bahkan Blob untuk data yang diberikan server, JSON merupakan format

yang paling umum. Intinya adalah kita dapat menggunakan format apapun untuk

bertukar data, selama klien dan server mengerti format tersebut.

Berbicara dengan Server

Mengirimkan data atau perintah ke server WebSocket dapat dilakukan dengan

menggunakan method ws.send. Penggunaannya sangat gamblang:

1

2

3

4

5

6

7

8

9

10

ws.send("Data Server"); // mengirimkan string

// atau bahkan

var obj = {

message: "Sebuah Pesan Rahasia",

key: "F5-A1-00-32-E4",

command: "Run"

};

ws.send(JSON.stringify(obj));

ws.send menerima hanya satu parameter, yang dapat

berisi DOMString, ArrayBuffer, maupun Blob. Pada kode di atas kita hanya

menggunakan string (DOMString) saja, bahkan untuk objek yang akan dikirimkan

ke server.

Studi kasus

Page 30: Java Script Lanjutan

Sekilas penggunaan WebSocket terlihat cukup mudah dan sederhana. Untuk lebih

mendalami pengertian akan WebSocket, kita akan langsung mencoba membangun

aplikasi klien WebSocket. Ingat, terlebih dahulu kita perlu server khusus

dalam ujicoba ini. Silahkan lihat bagian Persiapan Eksperimen WebSocket untuk

detail aplikasi server yang dibutuhkan dalam eksperimen ini.

Kasus 1: Aplikasi Chatting

Aplikasi yang paling pertama akan kita kembangkan adalah aplikasi chatting

sederhana. Agar dapat berfokus pada pengiriman dan penerimaan pesan saja,

kita akan menggunakan kode HTML yang sangat sederhana, sebagai berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Websocket test</title>

</head>

<body>

<ul id="chat"></ul>

<input type="text" id="chatinput">

<script type="text/javascript" src="chat.js"></script>

</body>

</html>

Selanjutnya, kita akan mengisikan chat.js dengan kode koneksi ke server

WebSocket, sesuai dengan yang kita pelajari sejauh ini:

1

2

3

4

5

6

7

8

var chat = document.querySelector("#chat"),

chatinput = document.querySelector("#chatinput"),

websocket = new WebSocket("ws://127.0.0.1:8080"), // #1

addChat = function (data) { // #2

var newChat = document.createElement("li"),

newText = document.createTextNode(data);

Page 31: Java Script Lanjutan

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

newChat.appendChild(newText);

chat.appendChild(newChat);

};

// #3

websocket.onmessage = function (event) {

addChat(event.data);

}

// #4

chatinput.addEventListener("keydown", function (evt) {

if (evt.keyCode === 13) {

addChat(chatinput.value);

websocket.send(chatinput.value); // #5

chatinput.value = "";

return false;

}

});

Penjelasan kode (sesuai dengan nomor yang diberikan pada komentar):

1. Pembuatan objek WebSocket untuk membuka koneksi dengan server. Pastikan

IP dan port yang digunakan benar pada bagian ini.

2. Fungsi addChat merupakan fungsi yang akan kita gunakan untuk

menambahkan chat baru ke elemen #chatinput.

3. Setelah membuat semua variabel dan fungsi yang dibutuhkan, kita

kemudian mengikatkan WebSocket.onmessagekepada satu fungsi anonim.

Fungsi ini tugasnya sangat sederhana: menambahkan chat baru dengan data

yang didapatkan dari server. Hal ini berarti chat baru yang ditambahkan

melalui WebSocket.onmessage selalu adalah chat yang dikirimkan oleh

pengguna lain.

4. Pada langkah ini kita menambahakn pemantau event keydown pada #chat,

yang akan mengirimkan data ke server ketika pengguna menekan tombol

Enter (key code 13).

Page 32: Java Script Lanjutan

5. Mengirimkan data ke server sangat sederhana, cukup dengan satu baris

perintah ini saja.

Seperti yang dapat kita lihat, implementasi WebSocket, baik dari sisi

pengiriman data ke server maupun pengolahan data yang diterima dari server

cukup mudah. Yang menjadi tantangan dalam penggunaan WebSocket biasanya

adalah kapanpengiriman data dilakukan, dan apa yang harus dilakukan terhadap

data yang dikirimkan oleh server.

Berikut adalah tampilan akhir dari aplikasi yang kita kembangkan:

Page 33: Java Script Lanjutan

Pemrograman Asinkron

Pada bagian sebelumnya, kita telah melihat dua model pemrograman asinkron,

yaitu AJAX dan WebSocket. Kedua model pemrograman ini memiliki pola

pemrograman yang sama, yaitu:

1. Kirimkan data atau perintah ke server secara asinkron.

2. Buat kode yang akan menangani respon dari server.

3. Lanjutkan kode aplikasi.

4. Ketika server telah mengembalikan data, jalankan kode pada no 2.

Model pemrograman yang menunggu sesuatu terjadi untuk kemudian menjalankan

kode tertentu seperti ini kita kenal dengan nama Event-Based

Programming (EBP). Meskipun dapat bekerja dengan sangat baik, model EBP

seperti ini cukup kompleks dan dapat menyebabkan kode program menjadi sulit

untuk dirawat. Misalkan kode seperti berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

$.ajax("/feature/", function(html) {

// (#1) melakukan sesuatu

$.ajax("/feature/subfeature", function(css) {

// (#2) melakukan sesuatu yang lebih kompleks

$.ajax("/feature/subfeature2", function() {

// (#3) melakukan sesuatu lagi

});

// (#4) lanjut eksekusi #2

});

// (#5) lanjut eksekusi #1

Page 34: Java Script Lanjutan

});

Pada format pemrograman di atas yang mengandalkan fungsi anonim

sebagai callback terhadap sebuah event yang terjadi menyebabkan perawatan

program lebih kompleks dari seharusnya. Jika misalnya terdapat kesalahan pada

bagian #3, kita akan kesulitan mendapatkan informasi lengkap (biasanya *stack

trace*) dari kode di atas. Kesulitan ini disebabkan berlapisnya fungsi anonim

yang digunakan, dan terkadang pesan kesalahan atau Exception yang dilemparkan

oleh fungsi anonim di dalam belum tentu dapat dibaca oleh fungsi luarnya.

Selain masalah di atas, umumnya juga sering terjadi kesulitan dalam mengikuti

alur eksekusi kode program seperti di atas. Contohnya, ketika #2 berjalan,

fungsi yang menampung #3 dapat saja dijalankan sebelum atau sesudah #4,

tergantung dari banyak faktor. Hal yang sama juga ditemui untuk

eksekusi #2 dan #5 (otomatis diikuti oleh eksekusi #3 serta #4). Masalah lain

lagi yaitu ketika kode di bagian #4 bergantung pada hasil yang ada pada #3.

Kita harus menggunakan mekanisme event yang lebih kompleks lagi,

yaitu callback, untuk memastikan #4 berjalan setelah #3.

Permsalahan-permasalahan yang dikemukakan di atas kemudian melahirkan

konstruk pemrograman baru [1], yang diharapkan dapat membantu kita dalam

menulis program asinkron.

Promise

Promise merupakan sebuah objek yang merepresentasikan sebuah nilai yang belum

ada sekarang, tetapi akan ada pada satu titik di masa depan. Contohnya, kita

dapat menggunakan Promise untuk mengambil data dari lokasi luar (misal:

datatweet pada Twitter). Ketika Promise dibuat, nilai dari data yang belum

datang tidak mungkin diketahui. Untuk menanggulangi hal ini, Promise akan

bertindak sebagai penengah sementara sampai data selesai diambil. Sementara

Promise sedang bekerja di balik layar, kita dapat memperlakukan objek Promise

layaknya nilai kelas pertama. Hal ini berarti kita dapat menyimpannya ke

dalam variabel, mengirimkan objek ke fungsi, mengembalikan objek dari fungsi,

dan apapun yang dapat dilakukan oleh variabel lainnya.

Kemampuan untuk memperlakukan operasi asinkron layaknya sebuah nilai kelas

pertama ini akan sangat memudahkan kita dalam melakukan pemrograman asinkron.

Sederhananya, kita dapat menulis kode asinkron yang seolah-olah adalah kode

sinkron. Hal ini tentunya akan sangat menyederhanakan kode program kita, yang

pada akhirnya berimbas pada kemudahan perawatan kode.

Pembuatan Objek Promise

Page 35: Java Script Lanjutan

Membuat objek Promise sendiri dapat dilakukan dengan sangat sederhana:

1

2

3

4

5

6

7

8

9

var promise = new Promise(function (resolve, reject) {

// Kode asinkron (AJAX, WebSocket, dll)

if (/* semuanya lancar tanpa error */) {

resolve(data);

} else {

reject(Error("Terjadi kesalahan."));

}

});

Kita hanya cukup memanggil constructor dari objek promise, yang menerima satu

fungsi. Fungsi yang diberikan kepadaPromise dapat diisikan dengan dua

parameter, yaitu:

1. Parameter pertama yang adalah sebuah fungsi yang dijalankan jika kode

asinkron telah selesai berjalan, dan berjalan tanpa masalah.

2. Parameter kedua sifatnya opsional, berisi fungsi yang dijalankan ketika

terjadi kesalahan dalam eksekusi kode asinkron.

Isi dari badan fungsi yang dikirimkan ke Promise sendiri tidak dibatasi.

Misalnya, kita dapat mengisikan fungsi tersebut dengan pemanggilan AJAX

seperti berikut:

1

2

3

4

5

6

7

8

9

10

11

12

var promise = new Promise(function (resolve, reject) {

var xhr;

try {

xhr = new XMLHttpRequest();

} catch (e) { reject(Error("XHR tidak didukung browser.")); }

xhr.onreadystatechange = function () {

if (xhr.readyState === 4 && xhr.status === 200) {

resolve(xhr.responseText);

}

Page 36: Java Script Lanjutan

13

14

15

16

17

};

xhr.open('GET', 'http://example.com/testajax/');

xhr.send();

});

Seperti yang dilihat dari kode di atas, kita pada dasarnya melakukan

pemanggilan AJAX di dalam fungsi yang dikirimkan kePromise. Perbedaan dari

kode yang kita tulis di atas adalah pemanggilan

fungsi resolve dan reject ketika kode AJAX berhasil ataupun gagal berjalan.

Sebuah Promise yang telah kita buat dapat memiliki tiga status keadaan:

1. Pending, yaitu jika nilai hasil eksekusi asinkron Promise belum dapat

diakses.

2. Fulfilled, yaitu ketika nilai sudah dapat diakses. Nilai ini nantinya

akan menjadi nilai permanen dari Promise.

3. Rejected, yaitu nilai yang didapatkan kalau eksekusi asinkron gagal

berjalan. Sama seperti fulfilled, nilai dari rejectedakan diasosiasikan

kepada Promise secara permanen. Nilai rejected biasanya berupa

objek Error, meskipun tidak terdapat batasan khusus apa yang harus kita

isikan di sini.

Ketika Promise dibuat, secara otomatis Promise akan berada pada

status pending. Kita kemudian dapat menggunakanPromise selayaknya variabel

biasa. Utilisasi dari hasil eksekusi asinkron Promise (setelah status berubah

menjadi fulfilledatau rejected) sendiri harus dilakukan melalui

pemanggilan method khusus.

Mengambil Hasil Eksekusi Promise

Meskipun Promise dapat digunakan layaknya variabel sembari menjalankan

eksekusi asinkron di balik layar, sampai satu titik tertentu kita tetap akan

harus mendapatkan hasil eksekusi tersebut. Ketika ingin mengakses nilai hasil

eksekusi asinkron dari Promise kita dapat memanggil method then, seperti

berikut:

1

2promise.then(

Page 37: Java Script Lanjutan

3

4

5

6

7

8

function (data) {

// jika promise sukses dijalankan

},

function (error) {

// jika promise gagal dijalankan

}

);

Method then menerima dua argumen: sebuah fungsi yang dipanggil

ketika Promise selesai dijalankan (fulfilled), dan sebuah fungsi yang

dijalankan ketika Promise gagal dijalankan (rejected). Kedua parameter ini

sifatnya opsional, sehingga kita dapat menambahkan hanya salah satu dari

fungsi tersebut.

Beberapa hal yang perlu diingat mengenai akses hasil eksekusi

dan method then:

1. Sebuah Promise hanya bisa berhasil atau gagal dieksekusi satu kali

saja. Sebuah Promise yang sudah berhasil atau gagal dijalankan juga

tidak dapat berubah status (misal: awalnya gagal, kemudian menjadi

berhasil). Hal ini berarti hasil eksekusi Promise akan selalu konsisten

begitu selesai dijalankan.

2. Jika Promise telah selesai dijalankan (tidak perduli berhasil atau

gagal), dan kita memasukkan fungsi baru untuk dijalankan jika

berhasil, Promise akan memanggil kembali fungsi tersebut dengan data

terakhir.

Kedua hal di atas sangat membantu kita dalam melakukan pemrograman asinkron,

karena kita tidak lagi harus pedulikapan sesuatu dapat diakses, melainkan apa

yang harus dilakukan ketika hal tersebut dapat diakses.

Promise Berantai

Seringkali ketika kita melakukan operasi asinkron, kita ingin melanjutkan

satu operasi asinkron dengan operasi asinkron lainnya. Misalnya, katakanlah

kita ingin mengambil data timeline dari Twitter beberapa pengguna, dan

kemudian menyusun data tersebut sesuai tanggal penulisan. Ketika pengambilan

data dari beberapa pengguna, tentunya kita harus melakukan beberapa

pemanggilan asinkron secara berkesinambungan dan memastikan seluruh

pemanggilan tersebut telah selesai sebelum mulai menyusunnya.

Page 38: Java Script Lanjutan

Kita dapat menggunakan dua cara untuk melakukan pemanggilan Promise secara

berantai seperti yang dijelaskan sebelumnya, yaitu:

1. Mengembalikan objek Promise pada fungsi yang dikirimkan ke then, dan

kemudian memanggil then dari fungsi tersebut lagi.

2. Menggunakan method Promise.all yang dirancang untuk memanggil

beberapa Promise sekaligus.

Mari kita langsung lihat metode yang pertama terlebih dahulu. Asumsikan kita

memiliki sebuah fungsi yang mengembalikan Promise seperti berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// MyLib.AJAX merupakan fungsi untuk pemanggilan AJAX

// yang dibahas pada bab sebelumnya.

var get = function (url, success, fail) {

MyLib.AJAX({

onSuccess: success,

onFailed: fail,

url: url,

method: "GET"

});

},

getPromised = function (url) {

return new Promise(function (resolve, reject) {

get(url, resolve, reject);

});

};

Kita kemudian dapat menggunakan getPromised seperti berikut:

1

2

3

4

5

6

7

var promise = getPromised("https://example.com/api/testing");

promise.then(function (data) {

// lakukan sesuatu

});

Page 39: Java Script Lanjutan

8

9

10

// atau langsung:

getPromised("https://example.com/api/testing").then(function (data) {

// lakukan sesuatu

});

Ketika kita mengembalikan nilai dari fungsi yang diberikan pada then, kita

dapat menyambung pemanggilan then untuk melakukan operasi lebih lanjut kepada

nilai tersebut:

1

2

3

4

5

6

7

8

getPromised("https://example.com/api/testing").then(function (data) {

// lakukan sesuatu

console.log(data); // asumsi: data = 10

return data + 1;

}).then(function (val) {

console.log(val); // 11 (data + 1)

});

Dengan prinsip yang sama, ketika kita mengembalikan objek Promise di dalam

fungsi then, maka operasi Promise pada fungsi kedua hanya dapat

dijalankan setelah operasi pertama selesai. Perhatikan kode berikut:

1

2

3

4

5

6

7

8

9

10

11

12

getPromised("https://example.com/api/testing")

.then(function (data) {

// lakukan sesuatu

// ...

return getPromised("https://example.com/api/percobaan");

})

.then(function (data) {

// fungsi ini hanya berjalan SETELAH

// then pertama selesai.

});

Page 40: Java Script Lanjutan

Karena then yang pertama baru akan dijalankan setelah pemanggilan

ke https://example.com/api/testing selesai, maka dengan mengembalikan

sebuah Promise baru kita akan memastikan then kedua hanya berjalan

setelah Promiseselesai berjalan.

Cara lain untuk menjalankan beberapa Promise sekaligus adalah dengan

menggunakan method Promise.all. MethodPromise.all menerima sebuah array

dari Promise, yang akan dijalankan dan dikembalikan hasilnya kepada kita pada

fungsi then:

1

2

3

4

5

6

7

8

var p1 = getPromised("https://example.com/api/testing");

var p2 = getPromised("https://example.com/api/percobaan");

var allP = [p1, p2];

Promise.all(allP).then(function (results) {

// results adalah array berisi hasil dari

// p1 dan p2, berurutan

});

Seperti yang dapat dilihat pada kode di atas,

fungsi then pada Promise.all sedikit berbeda, karena memberikan kita akses

kepada hasil dari eksekusi seluruh promise yang dikirimkan, secara berurutan

di dalam sebuah array. Sedikit kekurangan dari Promise.all adalah jika

terdapat satu saja Promise yang gagal dijalankan, maka semua Promise yang

dikirimkan akan dianggap gagal.

Perlombaan Promise

Ketika mengembangkan aplikasi yang bergantung kepada data asinkron, terkadang

kita hanya memerlukan salah satu sumber data saja, tetapi menggunakan

beberapa sumber untuk mendapatkan data yang tercepat ataupun terbaik.

Misalnya, kita sedang mengembangkan aplikasi pemetaan yang mengambil data

dari Google Maps (GM) dan Open Street Map (OSM). Kita dapat saja ingin

menampilkan peta secepatnya, tidak peduli apakah data peta berasal dari GM

atau OSM. Setelah mendapatkan peta, tentunya kita tidak ingin mengambil peta

yang satunya lagi, untuk menghemat bandwidthpengguna. Untuk dapat melakukan

hal ini, kita dapat menggunakan method Promise.race.

Promise.race menjalankan beberapa Promise sekaligus, dan kemudian mengambil

hasil Promise pertama yang selesai (atau gagal) dieksekusi.

Objek Promise lainnya yang belum selesai dieksekusi akan dihentikan begitu

Page 41: Java Script Lanjutan

kita mendapatkan hasil. Cara kerjanya cukup sederhana, yaitu dengan

menjalankan semua Promise bersamaan dan mengambil yang pertama kali

memberikan respon. Berikut adalah contoh penggunaannya:

1

2

3

4

5

6

var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, "one"); });

var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "two"); });

Promise.race([p1, p2]).then(function(value) {

// value === "two"

});

Sama seperti Promise.all, kita mengirimkan sebuah array berisi

beberapa Promise ke Promise.race. Fungsi thenkemudian akan memberikan satu

nilai saja, yaitu nilai yang terlebih dahulu didapatkan. Dalam contoh kode di

atas, kita dapat melihat bahwa p2 pasti akan selesai dijalankan terlebih

dahulu, sehingga nilai value dapat dipastikan adalah “two”. Begitu kita

mendapatkan hasil dari p2, nilai dari p1 sudah menjadi tidak penting

karena value akan diisikan oleh hasil dari p2.

Penggunaan nilai awal ini juga berlaku bahkan ketika Promise yang lebih akhir

selesai gagal dijalankan:

1

2

3

4

5

6

7

8

9

10

11

var p3 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "three"

var p4 = new Promise(function(resolve, reject) { setTimeout(reject, 500, "four"); });

Promise.race([p3, p4]).then(

function(value) {

// value === "three"

},

function(reason) {

// tidak dieksekusi

}

);

Bahkan ketika salah Promise terlebih dahulu gagal, Promise lain yang mungkin

memberikan hasil juga tidak lagi diperhitungkan hasilnya:

Page 42: Java Script Lanjutan

1

2

3

4

5

6

7

8

9

10

var p5 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, "five"

var p6 = new Promise(function(resolve, reject) { setTimeout(reject, 100, "six"); });

Promise.race([p5, p6]).then(

function(value) {

// tidak dieksekusi

}, function(reason) {

// reason === "six"

}

);

Berdasarkan prilaku dari Promise.race yang mengedepankan Promise tercepat

inilah kita memberikan nama “Perlombaan Promise”.

Javascript History API

Page 43: Java Script Lanjutan

Location Bar (tempat mengisikan URL) dan tombol Back merupakan dua elemen

yang paling banyak digunakan pada sebuah browser [1]. Sebagai elemen

terpopuler, tentunya sangat banyak pengguna yang bergantung pada kedua elemen

ini dalam melakukan navigasi website. Ketika ingin mengunjungi sebuah web,

kita memasukkan alamat web tersebut ke dalam Location Bar. Jika kita

berpindah-pindah halaman dalam satu jendela browser, kita lalu dapat kembali

ke halaman sebelumnya melalui tombol Back. Model navigasi seperti ini

merupakan model yang paling umum digunakan oleh pengguna awam.

Di dalam sebuah website sendiri biasanya terdapat elemen-elemen yang tidak

berubah antar halaman web, misalnya menu atau logo dari website. Ketika

pengguna berpindah dari satu halaman ke halaman lain maka pengguna harus

mengambil kembali elemen-elemen yang sama tersebut. Pengembang web modern

menghindari hal ini dengan menggunakan teknik seperti AJAX yang dapat

memperbaharui halaman web dengan menambah atau mengubah bagian-bagian yang

perlu diganti tanpa pengguna harus berpindah halaman. Penggunaan AJAX untuk

navigasi web seperti ini, sayangnya membuat tombol Back tidak lagi dapat

digunakan. AJAX memperbaharui halaman web tanpa berpindah halaman ini

maka browser tidak dapat mencatat sejarah browsing, yang menyebabkan tombol

Back tidak dapat digunakan. Hal ini seringkali mengecewakan para pengguna.

History API dari Javascript kemudian dikembangkan untuk menyelesaikan

permasalahan tombol Back yang tidak dapat digunakan pada website dengan fitur

AJAX ini. Fitur utama yang ditawarkan oleh History API adalah penelusuran dan

manipulasi sejarah browser. Adapun mayoritas dari History API dapat diakses

melalui objek window.history.

Langsung saja, mari kita lihat beberapa fitur yang ditawarkan.

Penelusuran Sejarah Browser

Penelusuran sejarah browser dapat dilakukan dengan sangat mudah,

melalui method khusus yang sudah disediakan

yaituhistory.back dan history.forward:

1

2

3

4

5

6

// mundur satu halaman ke belakang

window.history.back();

history.back(); // fungsinya sama dengan di atas

// maju satu halaman ke depan

history.forward();

Page 44: Java Script Lanjutan

Kita juga dapat bergerak ke posisi spesifik dalam sejarah, dengan

menggunakan method history.go. Method history.gomenerima satu parameter,

yaitu sebuah angka yang menentukan sejauh mana kita ingin bergerak relatif

terhadap posisi sekarang dalam sejarah. Hal ini berarti nilai positif akan

membuat kita bergerak maju, dan nilai negatif membuat kita bergerak mundur

dalam sejarah browser.

1

2

3

4

5

history.go(-1); // bergerak mundur ke 1 halaman sebelumnya

history.go(-5); // bergerak mundur ke 5 halaman sebelumnya

history.go(1); // bergerak maju 1 halaman

history.go(5); // bergerak maju 5 halaman

Jika kita tidak mengetahui dengan pasti ada berapa halaman ke belakang maupun

ke depan, kita dapat menggunakan properti history.length untuk melihat ada

berapa banyak total sejarah yang sudah tercatat.

1 var jlhSejarah = history.length;

Dengan menggunakan fungsi maupun properti di atas kita dapat mempermudah

navigasi halaman pengguna melalui kode program. Selanjutnya, kita akan

melihat bagaimana secara langsung menambahkan data sejarah baru ke browser.

Manipulasi Sejarah Browser

Terdapat dua method utama yang akan kita gunakan untuk melakukan manipulasi

sejarah browser,

yaituhistory.pushState dan history.replaceState. history.pushState berguna

untuk menambahkan catatan sejarah baru ke dalam browser,

sementara history.replaceState digunakan untuk memodifikasi catatan sejarah

terakhir (halaman yang sedang dibuka pengguna).

Langsung saja, kita akan melihat cara kerja dari masing-masing fungsi yang

disediakan untuk manipulasi sejarah browser.

Fungsi history.pushState

Seperti yang dijelaskan sebelumnya, history.pushState menambahkan sejarah

baru ke dalam browser. Hal ini berarti setiap kali kita

memanggil history.pushState browser akan memindahkan halaman yang sekarang

dengan data baru ke dalam history stack. Hal ini sedikit berbeda dengan

Page 45: Java Script Lanjutan

navigasi biasa yang mana browser memasukkan URL halaman baru ke dalam history

stack dan kemudian melakukan download kepada halaman baru tersebut.

history.pushState menerima tiga buah parameter, yaitu:

1. Sebuah objek yang menyimpan data sejarah. Objek ini dapat diisikan

dengan data apapun yang kita inginkan, dan idealnya berisi data yang

digunakan untuk menandai status halaman yang dibuka. Objek ini disebut

dengan objekstate. Objek state disimpan di dalam komputer lokal

pengguna, dengan batas maksimal 640k karakter ketika objek diserialkan

(misal dengan memanggil JSON.stringify). Jika memerlukan objek yang

lebih besar dari itu, gunakansessionStorage dan localStorage.

Objek state ini nantinya akan diberikan ke halaman yang sedang aktif

ketika pengguna menekan tombol Back (atau kembali ke halaman sebelumya

denganhistory.back maupun history.go). Objek diberikan

melalui event popstate.

2. Parameter kedua merupakan sebuah string, yang memberikan nama dari

sejarah yang akan dikunjungi. Sayangnya, parameter kedua ini belum

didukung mayoritas browser pada masa penulisan (September 2014)

sehingga parameter ini tidak melakukan apa-apa.

3. Sebuah string yang berisi URL baru. Browser tidak akan pindah ke URL

baru ini ketika kita memanggil pushState, melainkan hanya menggantikan

URL yang ada dengan URL baru ini. Begitupun, terdapat kasus di

mana browser akan membuka URL ini, misalnya ketika kita mematikan dan

menjalankan kembali browser. Parameter ketiga ini dapat diisikan dengan

URL relatif, tetapi harus dari domain yang sama. Jika URL yang

diberikan memiliki domain berbeda maka sebuah exception akan

dilemparkan. Parameter ketiga bersifat opsional. Jika tidak diberikan,

parameter ketiga diasumsikan adalah alamat URL sekarang.

Ketika menggunakan history.pushState, hal yang paling perlu diperhatikan

adalah data yang kita berikan pada parameter pertama. Sebagai data yang

menandakan keadaan (state) dari sebuah sejarah yang baru dibuat, biasanya

data ini lah yang menentukan tampilan atau bentuk halaman yang akan kita

berikan ke pengguna. Misalnya pada sebuah daftar artikel yang disimpan dalam

beberapa halaman, kita dapat mengirimkan nomor halaman selanjutnya seperti

berikut:

1var data = {

Page 46: Java Script Lanjutan

2

3

4

5

hal: halSelanjutnya

};

history.pushState(data, "Halaman " + halSelanjutnya, "/artikel/halaman/" + halSelanjutnya

Perhatikan bahwa data yang kita kirimkan berisi halaman selanjutnya, yakni

halaman yang akan kita tampilkan bukan halaman tempat sekarang pengguna

berada. Data yang kita kirimkan ini akan dapat diakses ketika pengguna

menekan tombol Back dari halaman berikutnya. Data kita akses

melalui event popstate.

Fungsi history.replaceState

history.replaceState merupakan method yang cara kerjanya sama persis

dengan history.pushState. Perbedaan utama method ini

dengan history.pushState adalah history.replaceState tidak menambahkan

catatan sejarah baru, melainkan langsung menggantikan state halaman yang

sedang dibuka sekarang.

Method ini sangat berguna terutama ketika kita ingin menambahkan state baru

ke halaman, berdasarkan apa yang dilakukan oleh pengguna.

Event PopState

Event PopState dijalankan oleh browser setiap kali terjadi pergerakan isi

sejarah dari satu dokumen yang sama. PopState hanya berjalan ketika

pergerakan sejarah dilakukan secara langsung atas permintaan pengguna, dengan

kata lain penekanan tombol Back dan Forward

atau history.back maupun history.go akan menjalankan PopState. PopState tidak

akan dijalankan

ketika history.pushState maupun history.replaceState dijalankan.

Ingat juga bahwa PopState hanya berjalan untuk satu dokumen yang sama. Hal

ini berarti ketika pengguna berpindah dokumen (misal

dari index.html ke about.html), maka PopState tidak akan dijalankan ketika

pengguna menekan tombol Back. Ketika mengembangkan aplikasi dengan History

API, kita hanya akan memiliki satu dokumen web saja, untuk menjaga

keberjalnjutan sejarah ini. Karenanya, aplikasi yang dibangun dengan

memanfaatkan History API sebagai pengendali dokumen dikenal dengan

nama Single Page Application (SPA).

Penggunaan event PopState sendiri tidak berbeda dengan event lainnya:

Page 47: Java Script Lanjutan

1

2

3

4

5

6

window.addEventListener("popstate", function (event) {

var stateData = event.state;

// kembalikan halaman ke state sebelumnya,

// sesuai dari data pada stateData

});

Beberapa hal yang perlu diperhatikan dari contoh penggunaan PopState di atas:

1. PopState diikatkan pada objek window. Hal ini penting, karena PopState

yang sifatnya global dan untuk seluruh halaman ini hanya dimiliki

oleh window saja.

2. Data yang kita akses pada event.state adalah data yang kita berikan

untuk parameter pertama

padahistory.pushState atau history.replaceState. Isi

dari event.state ini akan terus berubah setiap kali pengguna menekan

tombol Back atau Forward.

Hal lain yang juga perlu diingat adalah bahwa PopState tidak dijalankan

ketika kita pertama kali membuka sebuah dokumen HTML. Begitupun, PopState

akan tetap dijalankan ketika kita kembali membuka halaman pertama melalui

tomblback.

Kegunaan Praktis History API

Seperti yang telah dijelaskan pada bagian awal, fungsi utama dari History API

adalah untuk memastikan sejarah dari penelusuran pengguna tersimpan dalam

browser, bahkan ketika aplikasi kita mengandalkan AJAX sebagai metode

navigasi utama. Dalam prakteknya, tentunya kita tidak dapat semata-mata

langsung menggunakan History API pada setiap pemanggilan kode AJAX. Jika

dilakukan perubahan URL dan sejarah secara manual pada setiap pemanggilan

AJAX, kode yang kita hasilkan akan menjadi sulit dibaca dan dirawat.

Yang umumnya dilakukan untuk menjaga kerapihan kode adalah mengembangkan

sebuah pustaka khusus untuk memetakan URL dengan kode kita. Pustaka yang

mengatur pemetaan antara URL dengan kode dikenal dengan namaRouting Library.

Kita akan mencoba mengimplementasikan routing library pada bagian berikutnya.

Catatan Kaki

Page 48: Java Script Lanjutan

[1] Data dari Mozilla menunjukkan bahwa 95% pengguna menggunakan tombol Back, dan 92% pengguna menggunakan Location Bar.

Javascript Routing

Pada bagian ini kita akan membahas penggunaan History API untuk membangun

sebuah routing library sederhana. Tujuan utama dari pustaka yang ingin kita

kembangkan adalah untuk memetakan URL yang diakses user dengan fungsi atau

objek tertentu dalam kode kita. Misalkan ketika pengguna

mengakses http://contoh.com/profile/bertzzie maka

fungsiContoh.Profile("bertzzie") di dalam kode kita akan dipanggil. Karena

menggunakan History API, tentunya pengguna tidak perlu benar-benar berpindah

halaman (data bisa diambil menggunakan AJAX / WebSocket) dan sejarah

penelusuran dalam browser akan tetap diperbaharui.

Contoh penggunaan

Agar pembaca dapat lebih mudah memahami apa yang akan kita kembangkan, kita

terlebih dahulu akan melihat contoh penggunaan routing library yang akan

dikembangkan. Berikut adalah contoh penggunaan routing library yang akan kita

kembangkan:

1

2

3

4

5

6

7

var root = "/routing/", // route relatif dari http://contoh.com/routing/*

route = MyLib.Routes(root); // pembuatan objek routing

route.add(/profile\/(.*)/, function (pid) {

// kode dijalankan ketika pengguna mengakses

// http://contoh.com/routing/profile/*

Page 49: Java Script Lanjutan

8

9

10

11

12

13

14

});

route.add(/options\/(.*)/, function (type) {

// kode dijalankan ketika pengguna mengakses

// http://contoh.com/routing/options/*

});

route.init(); // inisialisasi semua route

Beberapa hal penting yang perlu diperhatikan dari kode di atas:

1. Pembuatan objek dilakukan melalui pemanggilan fungsi biasa,

yaitu MyLib.Routes.

2. Kita dapat memilih beberapa titik asal, yang disimpan pada

variabel root. Jika root berisi "/master/" maka seluruh route yang

dibuat akan dianggap relatif terhadap http://contoh.com/master/.

3. Penambahan route dilakukan dengan memanggil method Routes.add.

4. Pencocokan URL dilakukan menggunakan regular expression (dari parameter

pertama pada Routes.add).

5. Setelah semua route yang ada ditambahkan, kita harus tetap melakukan

inisialisasi melalui Routes.init.

Pada akhirnya, kode yang kita buat di atas cukup sederhana, dan terlihat

tidak jauh berbeda dengan kode frameworkaplikasi pada umumnya.

Dengan menggunakan routing library seperti pada kode di atas, secara otomatis

seluruh request yang datang dari pengguna akan hanya boleh datang dari satu

titik saja. Seluruh request harus masuk ke satu halaman yang sama, dan

kemudian request tersebut ditangani oleh kode router kita di atas. Karena

seluruh request masuk ke satu halaman (biasanyaindex.html), maka aplikasi

yang dibangun dengan cara seperti ini dikenal dengan nama “Single Page

Application (SPA)” [1].

Persiapan Awal

Sebelum mulai mengembangkan routing library ini, terdapat satu hal yang perlu

kita persiapkan terlebih dahulu, yaitu memastikan semua request pengguna

masuk ke satu titik pada kode kita saja. Jika kita ingin menggunakan routing

librarydengan optimal, kita harus dapat memastikan request pengguna, dalam

bentuk apapun, kembali ke index.html. Hal ini berarti ketika pengguna

Page 50: Java Script Lanjutan

mengakses http://contoh.com/profile/bertzzie (atau URL lainnya) sebenarnya ia

akan dibawa ke http://contoh.com/index.html di balik layar.

Untuk dapat mencapai hal ini, kita perlu melakukan konfigurasi melalui web

server yang digunakan. Silahkan baca dokumentasi pada web server yang anda

gunakan untuk melakukan hal ini [2]. Berikut adalah contoh konfigurasi yang

dapat digunakan jika anda menggunakan web server Apache httpd (yang biasa

dipaketkan dalam XAMPP [3]):

1. Pastikan ekstensi mod_rewrite telah aktif pada server anda (tutorial

linux, tuorial windows).

2. Buat sebuah file bernama .htaccess pada direktori utama aplikasi web

anda.

3. Isikan .htaccess dengan kode berikut:

1

2

3

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^(.*)$ index.html

Kemudian coba akses halaman secara acak pada URL relatif terhadap aplikasi

web anda. Jika anda menyimpan kode dihtdocs/routing/ maka akses

ke http://localhost/routing/url/acak/asdflak akan tetap menampilkan

isiindex.html sekarang.

Objek Pendukung

Hal lain yang perlu kita persiapkan sebelum mulai membangun routing

library kita adalah objek pendukung yang akan membantu kita dalam memproses

string URL yang akan kita olah. Kita akan mulai dengan membuat sebuah objek

sederhana. Buat sebuah file dengan nama URL.js dan isikan dengan kode

berikut:

1

2

3

4

5

6

7

8

var MyLib = MyLib || {};

(function () {

"use strict";

MyLib.URL = {

trimSlash: function (path) {

Page 51: Java Script Lanjutan

9

10

11

12

13

14

15

16

17

return path.toString().replace(/\/$/, '').replace(/^\//, '');

},

getPathName: function (url) {

var a = document.createElement("a");

a.href = url;

return a.pathname;

}

};

})(MyLib);

MyLib.URL merupakan sebuah objek sederhana yang hanya memiliki dua

buah method, yaitu:

1. trimSlash, sebuah method yang membantu kita dalam membuang garis miring

(slash; /) pada awal maupun akhir URL. Kita membuat method ini agar

rute seperti /profile/update/ dan /profile/update yang pada dasarnya

adalah sama, dapat dianggap sama oleh sistem kita nantinya. Selain

memotong garis miring pada akhir, kita juga memotong garis miring pada

awal, sehingga /route/ dan route dianggap sama.

2. getPathName, method yang mengambil pathname dari sebuah

URL. Pathname merupakan bagian URL yang muncul setelah URL dan

sebelum query data.

Contohnya, pathname dari http://www.google.com/search?q=testing adala

h/search. Kita ingin mengambil pathname karena biasanya bagian inilah

yang paling penting untuk routing (yang secara definisi menampilkan

halaman yang tepat untuk sebuah path).

Setelah membuat objek pendukung yang dibutuhkan, mari kita kembangkan objek

utama dari routing library kita.

Objek Router Utama

Langkah pertama untuk membuat routing library pastinya adalah membuat

objek router yang akan kita gunakan nantinya. Kode pembuatan objek sangat

sederhana, sesuai dengan prinsip awal yang kita pelajari pada Javascript:

Sebuah Pembedahan. Langsung saja, buat sebuah file dengan nama Routes.js,

dengan isi seperti berikut:

Page 52: Java Script Lanjutan

1

2

3

4

5

6

7

8

9

10

11

12

13

var MyLib = MyLib || {};

(function () {

"use strict";

MyLibs.Routes = function (r) {

var root = r? MyLib.URL.trimSlash(r) : "/",

routes = [],

fin = {};

return fin;

};

})();

Constructor objek utama kita menerima sebuah parameter opsional,

yaitu r. r merupakan “akar” atau rute awal yang kita inginkan untuk aplikasi

kita. Jika kita memasukkan nilai "/routing/" ke dalam r, maka semua rute yang

ditangani olehlibrary kita akan berawal

dari /routing/ (http://contoh.com/routing/profile ditangani

tetapihttp://contoh.com/about/profile tidak). Opsi ini tentunya sangat

berguna, memberikan fleksibilitas kepada kita untuk membangun apliksai dengan

beberapa titik awal rute berbeda. Jika dikosongkan, maka rute akar akan

otomatis menjadi/, yang artinya semua rute diproses.

Selanjutnya kita membuat sebuah array, routes, yang akan menyimpan seluruh

objek rute yang nantinya kita gunakan untuk memanggil fungsi yang dikaitkan

dengan rute. Rute dan fungsi yang akan dipanggil nantinya akan diisikan oleh

pengguna routing library kita. Setiap kali pengguna menambahkan rute baru

beserta dengan fungsi yang harus dipanggil ketika rute dipanggil, kita akan

membuat objek baru dan menyimpannya ke dalam array routes ini.

Terakhir, kita membuat objek fin, yang akan dikirimkan ke pengguna nanti.

Kita akan menambahkan banyak method ke dalam objek ini pada bagian

berikutnya.

Penambahan dan Penghapusan Rute

Page 53: Java Script Lanjutan

Fungsi paling pertama yang akan kita kembangkan ialah penambahan dan

penghapusan rute, karena fungsi inilah yang pertama kali akan digunakan oleh

pengguna. Langsung saja, tambahkan kode berikut sebelum return fin;:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

fin.add = function (pattern, handler) {

routes.push({'pattern': pattern, 'handler': handler});

return this;

};

fin.remove = function (pattern) {

var i = 0,

len = routes.length,

r;

for (i = 0; i < len; i += 1) {

r = routes[i].pattern.toString();

if (r === pattern.toString()) {

routes.splice(i, 1);

return this;

}

}

return this;

};

fin.reset = function () {

routes = [];

root = ''

};

Penambahan rute baru, melalui fin.add cukup sederhana. Method ini menerima

dua argumen: argumen pertama beruparegular expression yang digunakan untuk

mencocokkan pola rute, sementara argumen kedua adalah fungsi yang dipanggil

ketika rute cocok dengan URL. Kita hanya menambahkan objek baru ke dalam

Page 54: Java Script Lanjutan

array routes, dan kemudian mengembalikan this agar method dapat dipanggil

secara berantai jika diperlukan.

Penghapusan rute pada fin.remove sedikit lebih panjang, karena kita terlebih

dahulu harus menelusuri seluruh rute yang ada. Setiap rute dicek

apakah pattern-nya sama dengan rute yang akan dihapus, dan jika sama rute

tersebut kita buang dari array routes. Pembuangan array dilakukan

melalui Array.prototype.splice (dokumentasi splice) untuk menyederhanakan

fungsi.

Sebagai tambahan, kita juga membuat fungsi fin.reset yang hanya menghapus

semua rute, beserta dengan rute asal.

Masuk ke Rute Baru

Setelah bisa menambahkan rute baru, tentunya kita ingin memberikan fasilitas

kepada pengguna library untuk berpindah rute. Misalkan, pengguna web dapat

dibawa ke rute baru ketika melakukan klik sebuah tombol. Berikut adalah kode

untuk mencapai perpindahan rute ini:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

var Run = function (url) {

var path = url || fin.getCurrentPath(),

i = 0,

len = routes.length,

match;

path = MyLib.URL.trimSlash(path);

for (i = 0; i < len; i += 1) {

match = path.match(routes[i].pattern);

if (match) {

match.shift();

routes[i].handler.apply({}, match);

}

}

};

Page 55: Java Script Lanjutan

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

fin.getCurrentPath = function () {

var path = '';

path = MyLib.URL.trimSlash(location.pathname);

path = path.replace(/\?(.*)$/, '');

path = root != '/' ? path.replace(root, ''): path;

return MyLib.URL.trimSlash(path);

};

fin.navigate = function (path, title, state) {

path = MyLib.URL.trimSlash(MyLib.URL.getPathName(path));

Run(path);

history.pushState(state, title, "/" + root + "/" + path);

};

Run merupakan sebuah fungsi privat yang melakukan pencocokan pola URL

terhadap regular expression dari rute yang kita berikan pada fin.add. Jika

kita tidak memberikan nilai url kepada Run, maka eksekusi akan dilakukan

terhadap URL yang sedang dibuka pengguna pada saat itu (sehingga pengguna

tidak berpindah halaman). Pada fungsi Run, pada dasarnya kita menelusuri satu

per satu rute, dan mencocokkan polanya dengan

menggunakan methodString.prototype.match (dokumentasi match.

Karena String.prototype.match mengembalikan sebuah array sesuai dengan pola

yang kita berikan, kita kemudian dapat menggunakan fungsi apply [4] untuk

memanggil fungsi handleryang kita simpan ketika memanggil fin.add. Tentu saja

pemanggilan apply dilakukan setelah kita membuang elemen pertama dari array

hasil, karena elemen pertama merupakan pola dasar URL yang diberikan

(contohnya"/profile/bertzzie" dengan pola "/profile\/(.*)/" akan

mengembalikan ["profile/bertzzie", "bertzzie"], yang mana kita hanya

memerlukan "bertzzie").

Pengambilan URL pengguna sekarang dilakukan melalui fin.getCurrentPath.

Fungsi ini cukup gamblang, di mana kita hanya mengambil informasi URL

sekarang melalui location.pathname, dan kemudian melakukan pembersihan

terhadap data yang diberikan. Pembersihan yang dimaksud adalah dengan

Page 56: Java Script Lanjutan

menghapus garis miring di depan maupun belakang, serta penambahan root.

Fungsi ini dapat juga diletakkan pada MyLib.URL jika diinginkan. Kita

meletakkan fungsi ini padaMyLib.Routes dengan pertimbangan

bahwa currentPath atau pathname yang kita gunakan memiliki aturan spesifik

dari routing library kita (garis miring pembuka dan penutup harus dihapus,

rute asal, dst). Jika diletakkan pada MyLib.URL, kita pada dasarnya dapat

langsung mengembalikan location.pathname.

Terakhir, pengguna library dapat melakukan pemindahan rute melalui fungsi

publik fin.navigate, yang hanya melakukan pemanggilan Run dan kemudian

menyimpan perpindahan ini ke dalam sejarah

penelusuran browser melaluihistory.pushState. fin.navigate perlu dipisahkan

dengan Run terutama karena penyimpanan sejarah ini. Terkadang kita ingin

memanggil Run tanpa memindahkan sejarah, misalnya ketika pengguna menekan

tombol “Back”. Jika aksi pengguna menekan “Back” disimpan dalam sejarah, kita

akan memiliki perulangan sejarah sampai tidak terbatas.

Navigasi Link Otomatis

Untuk menambahkan fitur terakhir dari routing library, kita dapat membuat

sebuah fungsi yang akan mengubah semua link (elemen a pada HTML) untuk

menggunakan navigasi dari routing library kita. Beriktu adalah kode yang

digunakan:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

var HrefClickHandler = function (link, r) {

return function (e) {

e.preventDefault();

r.navigate(link.href, null, null);

};

};

fin.init = function () {

var links = document.querySelectorAll("a"),

i = 0,

len = links.length,

that = this,

link;

Page 57: Java Script Lanjutan

16

17

18

19

20

21

22

23

24

25

for (i = 0; i < len; i += 1) {

link = links[i];

link.addEventListener("click", HrefClickHandler(link, that));

}

window.onpopstate = function (e) {

Run(location.href);

};

};

Pertama-tama kita membuat closure HrefClickHandler yang akan menghasilkan

sebuah fungsi untuk menangani link (elemen DOM

dari a). HrefClickHandler menerima dua parameter, elemen DOM yang ingin

ditangani dan objekMyLib.Routes. Objek MyLib.Routes digunakan untuk melakukan

navigasi ke link sesuai dengan aturan yang telah kita tentukan, sementara

elemen DOM digunakan untuk referensi alamat yang akan dituju.

Method fin.init sendiri cukup sederhana: ambil semua elemen a yang ada,

kemudian tambahkan event click yang akan ditangani oleh HrefClickHandler.

Kita juga menambahkan pemantauan even popstate pada objek window, untuk

penanganan tombol “Back”. Hal ini berarti pengguna routing library mau tidak

mau harus melakukan pemanggilanfin.init ketika pertama kali memanggil

library. Jika anda tidak menginginkan hal ini, pantau event popstate pada

akhirconstructor.

Penutup

Pada akhir tulisan ini kita telah melihat bagaimana menggunakan History API

dengan praktis dan maksimal. Walaupun masih terdapat banyak kekurangan

dari routing library yang kita kembangkan, kita telah memanfaatkan History

API dengan efektif. Adapun beberapa kekurangan yang belum terimpelemntasi

dengan baik yaitu:

1. HrefClickHandler belum dapat menangani link eksternal. Jika tujuan link

yang diberikan oleh a adalah ke website

lain, HrefClickHandler seharusnya tahu dan tidak menanganinya

dengan MyLib.Routes.

Page 58: Java Script Lanjutan

2. Belum terdapat mekanisme atau method yang dapat digunakan ketika kita

ingin mengubah root secara dinamis.

3. MyLib.Routes belum menangani HTTP dengan baik. Misalnya, pengiriman

data form melalui POST atau PUT tidak akan dapat ditangani.

Implementasi perbaikan dari beberapa kekurangan di atas (dan pastinya masih

terdapat banyak kekurangan lain lagi) akan diserahkan sebagai latihan untuk

pembaca.

Kode lengkap dari routing library yang kita kembangkan, beserta contoh

penggunaannya dapat diambil pada halaman Github untuk artikel ini.

Catatan Kaki

[1] Dari sudut pandang Rekayasa Perangkat Lunak (Software Engineering) pola aplikasi seperti ini dikenal dengan namaFront Controller Pattern.

[2] Kata kunci yang umumnya digunakan adalah “Rewrite all URL to index.html/index.php”

[3] Pengguna nginx dapat mencoba mengakses tutorial berikut.

[4] Baca tentang Indirect Invocation Pattern jika tidak mengerti fungsi apply.

Page 59: Java Script Lanjutan

Javascript Module System

Pada bagian ini kita akan membahas proses melakukan organisasi kode program.

Ketika kita mengembangkan sebuah aplikasi kecil sederhana, organisasi kode

program bukan merupakan masalah. Aplikasi yang sederhana, yang katakanlah

hanya terdiri dari beberapa ratus baris kode, dapat disimpan di dalam sebuah

file dan masih tetap dapat dirawat dengan mudah. Namun seiring berkembangnya

aplikasi, seringkali kita akan mencapai satu titik di mana struktur program

dan fungsi-fungsi di dalamnya menjadi sulit dirawat (unmaintainable) dan

bahkan sulit dimengerti. Kode program yang awalnya mudah dimengerti dengan

fungsi-fungsi yang terfokus dan terpisah dengan baik menjadi kumpulan sayuran

yang menyerupai gado-gado: saling bercampur dan tidak kentara kegunaan dari

masing-masing komponennya.

Pada bahasa pemrograman lain, untuk menanggulangi hal ini kita melakukan dua

hal:

1. Memecah-mecah kode program menjadi banyak bagian-bagian yang lebih

kecil. Biasanya bagian kecil dari kode ini disebut dengan nama modul.

Setiap kode modul memiliki peranan spesifik, dan biasanya sebuah modul

terdiri dari beberapa fungsi. Semakin spesifik dan sejenis fungsi yang

terkumpul di dalam sebuah modul semakin baik. Tingkat kecocokan fungsi-

fungsi di dalam modul ini kita kenal dengan istilah cohesion.

2. Setelah kode program dipecah menjadi bagian-bagian kecil, masing-masing

komponen kecil ini kemudian dapat kita hubungkan untuk menjadi sebuah

komponen yang lebih besar atau bahkan program jadi.

Pembuatan modul dari kode program dapat dilakukan dengan banyak cara, seperti

mengumpulkan fungsi-fungsi ke dalam kelas atau objek, dan kmeudian memasukkan

kode tersebut ke dalam sebuah file. Bagian kedua, di mana kita dapat

memanggil modul-modul lain dengan mudah, biasanya didukung secara langsung

oleh bahasa pemrograman yang digunakan. Contohnya, pada bahasa Java kita

memiliki perintah import dan pada C# kita memiliki perintah using.

Page 60: Java Script Lanjutan

Javascript, sampai pada saat penulisan (November 2014), sayangnya belum

mengimplemenatsikan fitur ini secara alami di dalam bahasa (meskipun telah

direncanakan untuk ke depannya).

Karena belum diimplementasikan secara langsung oleh bahasa pemrogramannya,

situasi sistem manajemen modul pada Javascript belum terlalu baik. Terdapat

beberapa alternatif implementasi, yang berbeda-beda dan memiliki kelebihan

dan kekurangannya masing-masing. Kita akan mencoba melihat dan membahas

beberapa sistem yang paling populer pada bagian ini, yaitu AMD, CommonJS, dan

terakhir ES6 Harmony untuk melihat bagaimana Javascript akan

mengimplementasikan sistem manajemen modul kedepannya.

Persiapan Module System: Script Loader

Sebelum mulai membahas tentang module system, kita akan terlebih dahulu

membahas sebuah sistem lain yang akan selalu digunakan oleh module

system: script loader. Script loader merupakan sebuah sistem yang membantu

kita dalam melakukan pengambilan file-file kode yang dibutuhkan oleh module

system.

Karena terdapat banyak jenis dari script loader, masing-masing dengan

kelebihan dan kekurangannya sendiri, kita tidak akan membahas hal ini terlalu

dalam. Script loader yang akan kita gunakan adalah RequireJS.

AMD (Asynchronous Module Definition)

Tujuan dari pembuatan AMD adalah untuk menyediakan sebuah solusi dalam

mengembangkan kode modular Javascript. AMD dirancang agar kita dapat

mendefinisikan dan mengunakan modul secara asinkron. Sifat asinkron serta

fleksibilitas dari AMD membuat AMD banyak disukai oleh pengembang, dan

dianggap sebagai standar implementasi module system yang cukup baik sebelum

ES Harmony siap digunakan.

Module System pada AMD

Terdapat dua method utama yang perlu kita mengerti sebelu menggunakan AMD,

yaitu:

1. define digunakan untuk membuat sebuah model baru.

2. require digunakan untuk menggunakan modul yang telah didefinisikan,

menjadikan modul kita sekarang bergantung kepada modul lain.

Fungsi define dapat digunakan dengan cukup sederhana:

Page 61: Java Script Lanjutan

1

2

3

4

5

define(

module_id /*optional*/,

[dependencies] /*optional*/,

definition function /*function for instantiating the module or object*/

);

Seperti yang dapat dilihat dari kode di atas, bagian module_id bersifat

opsional, dan biasanya hanya digunakan ketika kita menggunakan sistem lain

yang tidak mendukung AMD. Jika module_id tidak diisikan, modul yang kita

gunakan disebut dengan modul anonim. Jika modul kita bersifat anonim, maka

nama dari modul akan dikenali sebagai nama file oleh AMD. Hal ini

memungkinkan kita untuk mengubah lokasi modul dengan bebas, tanpa harus

terikat dengan bagaimana kita menyimpan modul tersebut.

Parameter kedua, [dependencies], juga bersifat opsional. Parameter ini

merupakan sebuah array dari modul-modul lain yang akan digunakan di dalam

modul yang akan dibuat. Karena seringkali kita akan membuat modul yang tidak

bergantung dengan modul-modul lain, maka modul ini bersifat opsional.

Argumen ketiga (definition function) merupakan fungsi yang nantinya

dijalankan untuk menghasilkan modul baru kita. Bayangkan fungsi ini sebagai

constructor dari objek yang akan kita gunakan nantinya.

Berikut adalah contoh pembuatan sebuah modul sederhana:

1

2

3

4

5

6

7

8

9

10

11

12

13

define('myModule',

['foo', 'bar'],

// fungsi definisi modul

// perhatikan bahwa foo dan bar, dependensi dari modul,

// dijadikan parameter fungsi di sini.

function ( foo, bar ) {

// modul ini akan dikembalikan nantinya

// agar dapat digunakan oleh pengguna modul lain

var myModule = {

doStuff:function(){

console.log('Yay! Stuff');

}

Page 62: Java Script Lanjutan

14

15

16

17

}

return myModule;

}

);

Penggunaan modul sendiri dapat dilakukan dengan cukup sederhana:

1

2

3

4

5

require(['foo', 'bar'], function ( foo, bar ) {

// kode di sini

foo.doSomething();

});

Pada kode di atas, kita dapat menganggap foo dan bar sebagai sebuah fungsi

eksternal. Untuk menggunakan kedua fungsi ini kita memanggilnya melalui

parameter pertama dari require, dan kemudian mengirimkan kedua objeknya

melalui parameter fungsi. Cara ini merupakan bentuk paling sederhana dari

penggunaan modul pada AMD.

CommonJS

CommonJS merupakan standar yang lebih luas dari AMD, di mana ia mencakup

tidak hanya module system, tetapi juga paket-paket standar yang ada di dalam

Javascript. Kita dapat menyamakan CommonJS dengan pustaka standar pada bahasa

seperti Java atau C# (misal: system.out.* pada Java). Hal ini berarti selain

cara untuk membuat dan memanggil modul CommonJS juga mencakup berbagai modul

standar seperti modul input output, pembacaan file, dll.

Seperti AMD, CommonJS memiliki dua komponen utama untuk melakukan pembuatan /

pemanggilan modul:

1. exports merupakan sebuah objek global yang digunakan untuk menyimpan

modul.

2. require merupakan sebuah fungsi global yang dapat memanggil modul-modul

yang ada di dalam exports.

Langsung saja, berikut adalah contoh pembuatan modul pada CommonJS:

1// definisi fungsi atau objek atau modul

Page 63: Java Script Lanjutan

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// yang ingin kita buat

function foobar(){

this.foo = function(){

console.log('Hello foo');

};

this.bar = function(){

console.log('Hello bar');

};

};

// simpan agar fungsi foobar dapat digunakan

// di dalam modul lain

exports.foobar = foobar;

Seperti yang dapat dilihat pada kode di atas, pada CommonJS kita cukup hanya

menyimpan fungsi atau objek yang kita ingin gunakan pada modul lain ke

dalam exports. exports sendiri bersifat global, yang artinya dapat kita

panggil kapanpun, di manapun.

Untuk menggunakan fungsi foobar di atas kita dapat memanggil

fungsi require seperti berikut:

1

2

3

4

var foobar = require('./foobar').foobar,

test = new foobar();

test.bar(); // 'Hello bar'

Mirip seperti AMD, ketika kita memanggil modul dari CommonJS, pemanggilan

dilakukan melalui file, relatif terhadap modul yang sedang mengakses

sekarang. Jika dianalogikan, require('./foobar') pada kode di atas dapat

dianggap mengakses objek global exports yang ada pada file foobar.js.

Perbandingan AMD dan CommonJS

Sekilas CommonJS memang terlihat lebih sederhana untuk digunakan. Sayangnya,

terdapat banyak pengembang yang berpendapat bahwa CommonJS lebih cocok

Page 64: Java Script Lanjutan

digunakan hanya pada sisi server. Pendapat seperti ini didasarkan pada

berbagai modul bawaan pada CommonJS yang dianggap lebih condong ke penggunaan

Javascript pada sisi server misalnya I/O, system (pemanggilan program,

pembuatan proses, dkk). Fitur-fitur seperti ini tentu saja mustahil untuk

diimplementasikan pada sisi browser tanpa membuka lobang keamanan yang besar.

Hal ini kemudian menjadikan CommonJS gagal sebagai stanar de facto untuk

module system JavaScript, meskipun CommonJS digunakan secara luas pada

pemrograman sisi server seperti NodeJS.

AMD sendiri lebih menggunakan pendekatan yang mengutamakan browser dalam

pengembangannya. Fitur-fitur seperti pengambilan modul secara asinkron dan

kompatibilitas terhadap Javascript lama menunjukkan hal ini. Tanpa

menggunakan I/O file, AMD dapat mendukung berbagai jenis modul, dari pustaka

seperti jQuery sampai framework seperti Dojo. Semua jenis modul AMD juga

dapat dipastikan berjalan secara alami (native) dalam browser. Hal ini

membuat AMD menjadi sangat fleksibel.

Pendekatan module system dari ES Harmony sendiri sebenarnya lebih dekat

dengan CommonJS dalam beberapa hal seperti cara impor / ekspor modul

dibandingkan dengan AMD. Hal ini dikarenakan ES Harmony yang mencoba untuk

mengikutsertakan penggunaan Javascript pada server dan klien sebagai kasus

penggunaan module systemnya. Tanpa adanya fungsi standar yang berhubungan

dengan server, ES Harmony juga mendukung berbagai fitur baik dari AMD seperti

penggunaan modul asinkron.

Secara singkat, beberapa kelebihan utama dari AMD yaitu:

Pendekatan modul yang berjalan secara native di browser.

Fleksibel dan cukup sederhana untuk digunakan.

Definisi modul dibungkus dengan baik, tanpa harus memenuhi (mengotori)

objek global.

Dapat bekerja secara asinkron.

Tidak bergantung kepada sisi server.

Karena bersifat asinkron, kita dapat melakukan lazy loading jika

diperlukan.

Adapun kelebihan utama dari CommonJS adalah:

Memiliki banyak fungsi bawaan yang berguna.

Karena menggunakan sisi server, terdapat banyak fitur yang tidak

mungkin dimiliki implementasi lain.

Cara kerjanya lebih dekat dengan ES Harmony.

Page 65: Java Script Lanjutan

Lebih sederhana digunakan dibandingkan dengan AMD (masih dapat

diperdebatkan).

ES6 Harmony

Setelah melihat bagaimana AMD dan CommonJS mencoba menyelesaikan permasalahan

module system pada Javascript, sekarang kita akan melihat bagaimana

Javascript berencana untuk menyelesaikan masalah ini. Pada ES Harmony, konsep

dasar yang diguanakan untuk menyelesaikan masalah module system masih sama:

1. Perintah import mengikatkan nilai export dari sebuah modul untuk

digunakan secara lokal.

2. Perintah export membuat nilai-nilai yang ada di dalam sebuah modul

dapat dibaca (hanya baca, tidak dapat mengubah) oleh modul lain.

Perbedaan utama dari sistem yang disesiakan ES Harmony hanyalah pada

integrasi yang lebih ketat karena sifat native-nya. Tidak terdapat perbedaan

yang terlalu banyak dibandingkan AMD, CommonJS, dan bahkan bahasa pemrograman

lain pada implemenatsi module system ES Harmony. Faktanya, implementasi yang

dibuat sangat umum dan sederhana sehingga kebanyakan programmer akan langsung

dapat mengerti maksud dan cara penggunaan kode module system ES Harmony,

misalnya seperti berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

module staff{

// spesifikasikan export untuk nilai

// yang dapat diakses modul lain

export var baker = {

bake: function( item ){

console.log('Woo! I just baked ' + item);

}

}

}

module skills{

export var specialty = "baking";

export var experience = "5 years";

}

Page 66: Java Script Lanjutan

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

module cakeFactory{

// hanya import bagian tertentu saja

import baker from staff;

// import semuanya

import * from skills;

export var oven = {

makeCupcake: function( toppings ){

baker.bake('cupcake', toppings);

},

makeMuffin: function( mSize ){

baker.bake('muffin', size);

}

}

}

Kita bahkan dapat menggunakan modul yang berada pada server lain dengan ES

Harmony, seperti berikut:

1

2

3

module cakeFactory from 'http://addyosmani.com/factory/cakes.js';

cakeFactory.oven.makeCupcake('sprinkles');

cakeFactory.oven.makeMuffin('large');

Penutup¶

Pada bagian ini kita telah melihat beberapa pilihan moduel system pada

Javascript. Module system memiliki kelebihan jika dibandingkan dengan

penggunaan fungsi maupun objek global pada Javascript yang biasa kita

gunakan. Keuntungan utamanya yang didapatkan misalnya kita tidak lagi perlu

mengkhawatirkan urutan pemasukan file pada tag <script>yang digunakan.

Page 67: Java Script Lanjutan

Pembaca sangat direkomendasikan untuk setidaknya mencoba salah satu dari

CommonJS atau AMD sebelum melanjutkan ke bab berikutnya, karena pada bagian

framework kita akan menggunakan module system sepenuhnya.

Framework Javascript

Pada bagian ini kita akan melihat apa yang dimaksud dengan Framework secara

umum, serta berbagai contoh framework yang ada pada Javascript. Tujuan utama

kita mempelajari ini adalah karena pada pengembangan aplikasi yang berukuran

signifikan (katakanlah, lebih dari 1.000 baris), umumnya kita akan menemui

banyak kode-kode yang serupa dengan beberapa parameter atau nilai berbeda.

Ketika hal ini terjadi, kita perlu mengembangkan apa yang dikenal dengan

abstraksi. Mengutip Wikipedia:

Pada ilmu komputer, abstraksi merupakan proses memisahkan inti pemikiran (ide; gagasan) dari contoh (kejadian) spesifik ketika gagasan tersebut diimplementasikan.Struktur komputasi dari gagasan didefinisikan melalui makna (semantik) mereka, dengan menyembunyikan detil dari cara kerja gagasan tersebut.- Abstraction (Computer Science)

Ketika mengembangkan aplikasi yang relatif besar, pada umumnya kita akan

menemukan bagian dari aplikasi yang berulang. Misalnya, sebuah aplikasi yang

perlu mengakses basis data akan memiliki kode untuk melakukan koneksi dan

pengiriman perintah ke basis data. Meskipun perintah-perintah yang dikirimkan

berbeda, umumnya langkah untuk mengirimkan perintah tidak jauh berbeda:

1. Koneksi ke basis data

2. Kirimkan perintah

3. Proses respon

Ketiga langkah di atas dapat kita anggap sebagai implementasi dari sebuah

gagasan (inti pemikiran) umum. Inti pemikiran yang ada pada langkah di atas

adalah berhubungan dengan basis data. Karena hal ini akan dilakukan berulang

Page 68: Java Script Lanjutan

kali dalam sebuah aplikasi, akan sangat baik jika kita memiliki sebuah

gagasan umum yang membungkus ketiga langkah di atas menjadi hanya “kirim

perintah ke basis data” tanpa perlu memikirkan detil langkahnya. Dengan

begitu, makna semantik dari apa yang kita lakukan (“kirim perintah ke basis

data”) tidak perlu terganggu oleh detil implementasi. Hal inilah yang kita

kenal sebagai abstraksi dalam ilmu komputer.

Abstraksi memiliki banyak kelebihan:

1. Karena gagasan inti telah terpisah dari detil implementasi, secara

teori kita dapat mengganti detil implementasi tanpa perlu mengganti

gagasan inti. Pada contoh di atas misalnya, kita dapat mengganti basis

data (misal: dari MySQL ke Postgres) tanpa perlu mengganti kode-kode

lain yang menggunakan abstraksi kita. Kode yang diganti hanya kode

abstraksi yang menangani detil implementasi hubungan ke basis data.

2. Abstraksi umumnya membuka peluang untuk mengembangkan sebuah antarmuka

pemrograman yang sangat ekspresif dan kuat. Misalnya, dengan abstraksi

kita dapat memperluas sebuah gagasan (dari “kirim perintah ke basis

data” menjadi “akses data”) sehingga aplikasi yang dikembangkan di atas

abstraksi ini dapat memiliki interaksi dengan data yang berbeda tanpa

perlu tahu apa saja data tersebut. Sebagian data dapat datang dari

basis data, dan lainnya datang dari XML, tetapi aplikasi kita cukup

tahu bahwa data tersebut ada dan dapat diakses, tanpa perlu tau cara

membaca XML atau basis data.

3. Karena poin kedua, kompleksitas kode dari aplikasi akan otomatis

menurun. Ketika kita membangun di atas abstraksi, sebagai pengguna

abstraksi terdapat banyak detil implementasi yang tidak perlu kita

pikirkan, menyebabkan implementasi aplikasi menjadi lebih sederhana.

Hal ini secara otomatis akan mempermudah kita dalam mengembangkan

aplikasi.

Meskipun dapat sangat membantu kita dalam mengembangkan aplikasi, abstraksi

yang tidak diimplementasikan dengan hati-hati juga dapat menyebabkan hal

buruk. Ketika kita menggunakan sebuah abstraksi yang dikembangkan oleh orang

lain, tentunya kita harus mempelajari detil abstraksi tersebut sebelum dapat

menggunakannya dengan efektif. Hal ini seringkali menjadi sandungan dan

memperpanjang waktu pengembangan. Sebuah abstraksi yang tidak tepat juga

bahkan dapat mempersulit pengembangan aplikasi kita. Detil mengenai abstraksi

yang baik dan buruk sulit dijelaskan tanpa berpengalaman langsung bekerja

dengan abstraksi terlebih dahulu. Karena hal ini, kita akan membahas

Page 69: Java Script Lanjutan

kelebihan dan kekurangan abstraksi ini sembari mempelajari berbagai abstraksi

yang ada pada bagian-bagian selanjutnya.

Sebelum mulai masuk dan mencoba berbagai abstraksi yang ada, kita akan

melihat jenis-jenis abstraksi yang ditawarkan oleh lingkungan Javascript

terlebih dahulu. Secara umum, di lingkungan Javascript terdapat beberapa

jenis abstraksi yang dapat kita temui:

1. Library

2. Widget Toolkit

3. Framework

Mari kita lihat perbedaan dari masing-masing abstraksi ini.

Library

Sebuah library, atau pustaka kode, didefinisikan sebagai berikut pada tulisan

ini:

Kumpulan implementasi fungsi-fungsi umum dari perangkat lunak yang memiliki

perilaku spesifik

Fungsi yang dimaksudkan pada “kumpulan implementasi fungsi-fungsi umum” di

atas adalah fungsi dalam arti fungsionalitas, bukan fitur function pada

sebuah bahasa pemrograman. Sebuah library dapat menyediakan kumpulan

implementasi fungsionalitas untuk membaca file PDF atau melakukan

kalkulasi Fast Fourier Transform. Fitur bahasa yang digunakan

oleh library untuk mendapatkan sebuah fungsionalitas tertentu mungkin

saja function, class, atau yang lain. Cara library mengimplementasikan

sesuatu tidak terlalu penting, selama fungsionalitas yang diinginkan dapat

tercapai.

Fungsi-fungsi umum yang ada di dalam sebuah library umumnya memiliki perilaku

spesifik. Perilaku spesifik ini diartikan sebagai sebuah spesifikasi masukan

dan keluaran dari fungsi tersebut. Spesifikasi ini dapat mencakup tipe data

(masukan maupun keluaran), efek samping, paramter fungsi, nilai kembalian,

dan banyak hal lain. Tingkat kelengkapan spesifikasi dari

sebuah library sendiri berbeda-beda, dan tentunya semakin lengkap (spesifik)

detil spesifikasinya semakin baik pulalibrary tersebut.

Untuk memperjelas lagi, mari kita lihat contoh penggunaan sebuah library pada

aplikasi. Diagram berikut menunjukkan alur arus data sebuah aplikasi yang

menggunakan library:

Page 70: Java Script Lanjutan

Pada diagram di atas, kita ingin mengembangkan sebuah aplikasi yang dapat

memainkan file musik ogg vorbis. Terdapat dua buah library yang digunakan

oleh aplikasi kita, yaitu libvorbisfile dan libalsa. Alur kerja dari aplikasi

adalah kira-kira seperti berikut:

1. Pengguna memberikan file ogg kepada aplikasi.

2. Aplikasi memberikan file ogg kepada libvorbisfile.

3. libvorbisfile memproses file ogg dan memberikan kembali hasil proses

berupa stream audio ke aplikasi.

4. Aplikasi memberikan stream audio dari libvorbisfile ke libalsa.

5. libalsa memainkan stream audio tersebut dan mengeluarkan suaranya ke

perangkat audio seperti speaker.

Perhatikan bagaimana dengan menggunakan libvorbisfile dan libalsa aplikasi

kita tidak perlu lagi mengetahui cara mengubah file ogg menjadi stream audio

Page 71: Java Script Lanjutan

dan cara mengubah stream audio menjadi suara. Kita hanya mengirimkan data

yang dibutuhkan libvorbisfile maupun libalsa sesuai dengan spesifikasi

mereka, dan mendapatkan keluaran yang kita inginkan.

libvorbisfile sendiri, seperti yang dapat dilihat pada diagram di atas,

menggunakan dua buah library lain lagi,

yaitulibogg dan libvorbis. libogg digunakan untuk mengubah

file ogg menjadi vorbis stream, yang merupakan formatstream spesifik untuk

vorbis. Keluaran dari libogg ini kemudian diberikan kepada libvorbis untuk

diubah menjadistream audio standar. Penggunaan library lain di dalam

sebuah library ini merupakan hal yang sangat umum terjadi, dan pada akhirnya

tidak mengherankan jika aplikasi yang kita kembangkan akan memerlukan

banyak library.

Berdasarkan penuturan di atas, kita dapat menyimpulkan beberapa hal

tentang library:

1. Library merupakan kumpulan fungsi, yang kemudian dapat digunakan untuk

membangun aplikasi. Dari sudut pandang lain, kita dapat

menganggap library sebagai sebuah blok fungsi seperti lego yang dapat

digabungkan untuk menjadi sebuah bentuk (dalam kasus kita: apikasi

atau library yang lebih kompleks).

2. Sebuah library dapat digunakan dengan bebas, sesuai dengan kebutuhan.

Jika tidak ingin menggunakan sebuahlibrary, kita tetap dapat

mengimplementasikan fungsi yang diinginkan. Ketika ingin

menggunakan library pun, kita tidak perlu harus menggunakan semua

fungsionaltias yang disedikaan library tersebut.

3. Sebuah library yang baik biasanya menyediakan fungsi-fungsi yang

sejenis dan saling berhubungan. Prinsip ini kita kenal dengan

istilah *cohesion*. Semakin terfokus fungsi-fungsi yang ada di dalam

sebuah library semakin baik. Memiliki fungsi untuk menghitung luas

lingkaran di dalam library untuk memainkan file mp3 misalnya, tidak

akan menambahkan manfaat apapun selain beban pengujian dan perawatan

kode.

4. Sebuah library relatif mudah digunakan bersamaan dengan library lain

karenanya kita dapat dengan mudah menggunakan beberapa library dalam

satu aplikasi. Kendatipun terdapat library yang bergantung

kepada library lain (i.e. kita tidak dapat menggunakan library A tanpa

juga menggunakan library B), hal ini umumnya dihindari. Tingkat

ketergantungan antar library kita kenal dengan istilah coupling, dan

semakin rendah tingkat ketergantungan (coupling) semakin baik.

Page 72: Java Script Lanjutan

Contoh dari sebuah library pada lingkungan Javascript adalah jQuery. jQuery

menawarkan berbagai fungsionalitas umum yang biasanya digunakan pengguna

Javascript di dalam sebuah abstraksi sederhana yang mudah digunakan.

Misalnya, jika kita ingin menggunakan XHR, alih-alih menuliskan kode panjang

agar XHR dapat berjalan di semua browser, jQuery menawarkan fungsi .ajax yang

sederhana:

1

2

3

4

5

6

7

8

9

$.ajax({

url: "/api/getWeather",

data: {

zipcode: 97201

},

success: function(data) {

$("#weather-temp").html("<b>" + data + "</b> degrees");

}

});

Widget Toolkit

Setingkat di atas library, kita memiliki Widget Toolkit dalam dunia

Javascript. Definisi sederhananya adalah:

(Kumpulan) library untuk membuat elemen-elemen tertentu untuk mengembangkan

antarmuka (UI)

Widget Toolkit merupakan kumpulan library, atau terkadang

sebuah library besar yang dibangun di atas banyak librarykecil lainnya.

Karena merupakan kumpulan library, Widget Toolkit biasanya menspesifikasikan

bagaimana seluruh libraryyang digunakan saling berinteraksi. Hal ini berarti

terdapat coupling antara semua library yang digunakan oleh Widget Toolkit.

Sebuah Widget Toolkit seringkali juga bukan hanya menggunakan library sebagai

alat untuk membangun antarmuka pengguna, tetapi juga untuk membantu fitur-

fitur tertentu. Misalnya, sebuah Widget Toolkit dapat menggunakan jQuery

untuk berinteraksi dengan elemen-elemen antarmuka pengguna yang

disediakannya.

Karena sebuah antarmuka biasanya disertai dengan berbagai komponen pendukung

seperti ikon atau gambar latar, sebuah Widget Toolkit seringkali dipaketkan

bersamaan dengan komponen-komponen pendukung tersebut. Dalam lingkungan

Page 73: Java Script Lanjutan

Javascript, komponen-komponen pendukung ini dapat berupa CSS, gambar, font,

suara, dst.

Sebagai suatu abstraksi yang mencampurkan berbagai library dan komponen

antarmuka, sebuah Widget Toolkit biasanya memiliki cara kerja dan interaksi

antar komponen yang cukup spesifik. Hal ini menyebabkan Widget Toolkit sulit

digunakan bersamaan dengan Widget Toolkit atau bahkan library lain. Ketika

memutuskan untuk menggunakan sebuah Widget Toolkit, biasanya evaluasi akan

dilakukan dengan lebih hati-hati, karena pergantian Widget Toolkit biasanya

akan diikuti oleh pergantian seluruh komponen antarmuka beserta

dengan library yang digunakan.

Untuk memperjelas perbedaan antar Widget Toolkit ini, mari kita lihat sekilas

bagaimana tiga buah Widget Toolkit yang cukup populer (jQuery UI, Dojo

Toolkit, YUI) menampilkan sebuah widget untuk memilih tanggal (datepicker):

Kode (jQuery UI) Tampilan

Page 74: Java Script Lanjutan

Kode (Dojo) Tampilan

Kode (YUI) Tampilan

Dari ketiga Widget Toolkit yang ada di atas, kita dapat melihat bagaimana

baik tampilan hasil antarmuka maupun kode yang digunakan untuk menghasilkan

elemen tersebut sangat berbeda. Perbedaan paling mencolok tampak pada

tampilan yang dihasilkan. Karena kita tidak menambahkan CSS sendiri di sini,

tampilan yang dihasilkan didapatkan dari masing-masing CSS yang telah

dipaketkan oleh Widget Toolkit. Cara pembuatan elemen juga berbeda-beda. Pada

jQuery UI, kita dapat melihat bagaimana elemen dibuat dari pengembangan

Page 75: Java Script Lanjutan

elemen DOM hasil pengambilan melalui $("#datepicker"), sementara pada Dojo

kita langsung mengubah elemen HTML-nya.

Karena perbedaan cara kerja seperti ini, kita tidak dapat dengan mudah

langsung saling menggabungkan ketiga Widget Toolkit ini. Belum lagi jika pada

CSS yang dipaketkan terdapat styling terhadap elemen yang sama. Hal ini lah

yang terutama membedakan antara Widget Toolkit dengan library.

Framework

Framework dalam konteks perangkat lunak dapat kita definisikan sebagai

berikut:

Lingkungan pengembangan perangkat lunak yang menyediakan fasilitas

spesifik untuk membuat sistem baru

Sebuah framework biasanya menyediakan abstraksi yang memberikan berbagai

fungsi generik. Fungsi-fungsi generik ini kemudian dapat kita ubah atau kita

lengkapi untuk mengembangkan sebuah sistem baru. Dengan melengkapi dan

mengubah sistem ini dengan kode kita sendiri, idealnya kita dapat

menghasilkan sebuah aplikasi baru sesuai dengan kebutuhan.

Sebuah framework bukan hanya menyediakan fungsi seperti library, tetapi juga

sebuah lingkungan pegnembangan. Sebuah lingkungan pengembangan biasanya

disediakan framework untuk memfasilitasi kita dalam mengembangkan apliaksi.

Lingkungan pengembangan dapat saja mengikut sertakan compiler, sekumpulan

aplikasi pendukung, library, dan berbagai perangkat lainnya yang dapat saling

bekerja sama untuk membangun sebuah solusi.

Karena banyaknya komponen dalam sebuah framework ini,

sebuah framework biasanya lebih dogmatis dalam memandang cara pengembangan

perangkat lunak. Dari metode interaksi sampai dengan penamaan file tidak

jarang ditentukan olehframework. Sebagai pengguna framework, biasanya kita

hanya mengikuti aturan yang telah ditentukan oleh frameork, dan bekerja di

dalam lingkup framework tersebut. Hal ini juga menyebabkan kita sulit

menggunakan sebuah framework denganframework lainnya secara bersamaan.

Sebuah framework memiliki beberapa ciri khas yang membedakannya

dengan library pada umumnya:

1. Inversion of Control, yaitu keadaan di mana alur kerja dari aplikasi

kita dikontrol oleh framework, bukan penggunaframeowrk.

2. Standard, di mana sebuah framework memiliki berbagai perilaku dan alur

standar, dari nama file sampai alur program. Hal ini menyebabkan

Page 76: Java Script Lanjutan

pengguna framework yang tidak mengikuti perkembangan awal aplikasi

dapat dengan mudah terjun ke dalam pengembangan kapanpun.

3. Extensibility, yaitu framework dapat dikembangkan atau diubah melalui

mekanisme yang telah disediakan, biasnya plugin.

Spesifik terhadap dunia pengembangan web, terdapat beberapa

jenis framework yang umum kita temui, yaitu:

1. MVC (Model-View-Controller), merupakan framework yang membagi

arsitektur aplikasi ke dalam 3 bagian: Model (data), View (antarmuka),

dan Controller (aturan bisnis, penghubung Model dan View).

2. Pull (Component) Based Framework, merupakan framework yang berbasis

antarmuka, di mana terdapat komponen antarmuka dari framework yang

kemudian menarik data dari server (kontras dengan framework umum yang

mengirimkan antarmuka bersamaan dengan data).

3. n-tier Framework, framework yang membagi-bagi aplikasi ke dalam banyak

lapisan. Ukuran dan kegunaan dari lapisan sendiri tidak dibatasi.

Meskipun terdapat banyak jenis framework, pada dasarnya tujuan utama

dari framework adalah untuk memfasilitasi pengembang (pengguna framework)

fokus dalam mengembangkan aplikasi. Dengan menyediakan lingkungan

pengembangan dan berbagai komponen, sebuah fraemwork melepaskan kita dari

berbagai detil implementasi pendukung, sehingga kita dapat berfokus pada

aturan bisnis dan kebutuhan perangkat lunak yang ada.

Contohnya pada sebuah framework pengembangan web, umumnya akan terdapat

komponen dan mekanisme khusus untuk manajemen pengguna. Hal ini dapat

membebaskan pengembang dari kode untuk menyimpan dan mengambil statepengguna,

yang pada kebanyakan aplikasi adalah sama. Dengan menghindari repetisi

seperti ini kita dapat berfokus kepada fitur-fitur yang ada pada kebutuhan

perangkat lunak kita.

Page 77: Java Script Lanjutan

React JS (Pengenalan)

ReactJS merupakan sebuah library dari facebook yang dapat digunakan untuk

membangun antarmuka pengguna. Pada bagian ini kita akan mencoba menggunakan

React untuk membangun aplikasi sederhana, untuk melihat konsep-konsep inti

yang ditawarkan oleh React.

Sebelum mulai mencoba menggunakan React, beberapa prasyarat yang diperlukan

yaitu:

1. React Starter Kit  untuk berbagai file dari React

2. jQuery , sebagai library pendukung

Jika sudah mengambil kedua kebutuhan di atas, ekstrak React Starter Kit ke

dalam sebuah direktori dan jalankan sebuah web server lokal (misal: http-

server) di dalamnya. Seluruh eksperimen kita akan dijalankan dari direktori

ini.

Hello, React!

Page 78: Java Script Lanjutan

Untuk memulai eksperimen, kita akan langsung mencoba membuat sebuah halaman

sederhana dengan menggunakan ReactJS. Buat sebuah file dengan

nama index.html di dalam direktori utama starter kit ReactJS, dan isikan

dengan kode berikut:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<!DOCTYPE html>

<html>

<head>

<script src="build/react.js"></script>

<script src="build/JSXTransformer.js"></script>

</head>

<body>

<div id="content"></div>

<script type="text/jsx">

React.render(

<h1>Hello, world!</h1>,

document.getElementById('content')

);

</script>

</body>

</html>

Buka index.html pada browser dan lihat hasil eksekusinya.

Page 79: Java Script Lanjutan

Apa yang baru saja kita lakukan?

Pada bagian <head> dari index.html kita memasukkan semua modul Javascript

yang dibutuhkan oleh ReactJS.<div id="content"> merupakan elemen yang akan

menampung antarmuka yang kita hasilkan dengan menggunakan

ReactJS. React.render merupakan fungsi utama dari ReactJS, yang akan

menggambarkan antarmuka yang kita buat. Fungsi ini menerima dua buah argumen:

1. Argumen pertama merupakan bentuk dari keluaran antarmuka yang ingin

kita buat. Perhatikan bagaimana kita menggunakan sintaks

yang mirip dengan HTML di sini. Kode <h1>Hello, world!</h1> yang kita

isikan bukanHTML, melainkan sebuah sintaks khusus yang bernama JSX.

Perhatikan juga bahwa kita menggunakan<script type="text/jsx"> pada

Page 80: Java Script Lanjutan

awal tag <script>. Penjelasan lebih lanjut mengenai JSX akan kita

tambahkan nanti.

2. Parameter kedua menerima elemen DOM tempat kita ingin menampilkan

keluaran dari elemen pertama. Parameter ini cukup gamblang, dan kita

hanya mengirimkan elemen DOM standar yang didapat

daridocument.getElementById di sini.

Bentuk awal dari penggunaan ReactJS memang cukup sederhana. Kita akan melihat

bagaimana hampir keseluruhan pengembangan dari ReactJS berdasar dari model

sederhana ini nantinya.

Kode ReactJS pada File Terpisah

Jika diinginkan, kita juga dapat memisahkan kode JSX kita pada sebuah file

terpisah, layaknya kita memisahkan kode javascript biasa pada file lain.

Misalnya, kita dapat membuat sebuah file src/helloworld.js dengan isi:

1

2

3

4

React.render(

<h1>Hello, world!</h1>,

document.getElementById('content')

);

Dan tentunya kita harus menggantikan tag script pada index.html menjadi:

1 <script type="text/jsx" src="src/helloworld.js"></script>

Dapat dilihat bagaimana tidak terdapat perbedaan mencolok antara penggunaan

javascript dengan JSX, selain pada bagian di mana JSX dapat menerima kode

yang mirip HTML di dalamnya.

Kompilasi JSX ke Javascript

Jika ingin, kita dapat juga melakukan kompilasi JSX ke javascript, yang pada

kode sebelumnya dilakukan olehJSXTransformer.js secara otomatis dan langsung.

Kompilasi tentunya akan menghemat waktu eksekusi kode, karenabrowser dapat

langsung membaca kode javascript yang kita berikan tanpa perlu melakukan

transformasi dari JSX ke javascript lagi. Kompilasi dari JSX ke javascript

dapat dilakukan dengan menggunakan tools yang telah disediakan ReactJS,

melalui platform NodeJS.

Untuk dapat melakukan kompilasi, pertama-tama kita harus melakukan

instalasi tools:

Page 81: Java Script Lanjutan

1 npm install -g react-tools

Kita kemudian dapat mengubah src/hellworld.js yang berisi JSX menjadi

javascript dengan perintah:

1 jsx --watch src/ out/

Tentunya karena kita telah memiliki hasil kompilasi JSX, kita tidak lagi

perlu menggunakan JSXTransformer.js pada HTML kita, dan kita juga dapat

langsung memasukkan hasil kompilasi seperti berikut:

1

2

3

4

5

6

7

8

9

10

11

<!DOCTYPE html>

<html>

<head>

<script src="build/react.js"></script>

<!-- Tidak ada lagi JSXTransformer.js -->

</head>

<body>

<div id="content"></div>

<script src="out/helloworld.js"></script>

</body>

</html>

Perhatikan juga bagaimana kita tidak lagi memasukkan type="text/jsx" pada

tag <script>. Isi dariout/helloworld.js sendiri adalah seperti berikut:

1

2

3

4

React.render(

React.createElement('h1', null, 'Hello, world!'),

document.getElementById('content')

);

Dengan hanya perbedaan pada bagian sintaks JSX saja. Tentunya kita juga dapat

langsung menggunakan pemanggilan fungsi seperti yang ada pada file hasil

kompilasi ini jika mau.

Pembangunan Elemen Antarmuka ReactJS

Page 82: Java Script Lanjutan

ReactJS merupaakn sebuah library yang berbasis komponen. Hal ini menyebabkan

kita harus mengembangkan sebuah elemen antarmuka komponen demi komponen. Kita

akan langsung melihat bagaimana kita dapat mengembangkan sebuah komponen

ReactJS sederhana dengan menggunakan fungsi-fungsi yang ada.

Aplikasi percobaan yang akan kita bangun adalah sebuah todo list (TDL)

sederhana, yang menyimpan catatan berbagai hal yang akan kita lakukan.

Tampilan aplikasi sangat sederhana:

TDL yang akan kita kembangkan ini akan terdiri dari tiga buah komponen, yaitu

1. komponen yang menerima masukan pengguna untuk menambahkan data baru,

2. komponen yang menampilkan semua tugas pengguna yang telah tercatat

dalam sistem, dan

Page 83: Java Script Lanjutan

3. komponen utama TDL yang menampung kedua komponen sebelumnya.

Jika diilustrasikan, pembagian komponen kita dapat dilihat seperti gambar

berikut:

Langsung saja, kita dapat mulai membangun elemen antarmuka TDL ini dari file

HTML yang diperlukan. Buat sebuah filetodo.html dan isikan dengan kode

berikut:

1

2

3

4

<!DOCTYPE html>

<html lang="en">

<head>

Page 84: Java Script Lanjutan

5

6

7

8

9

10

11

12

13

14

15

<meta charset="UTF-8">

<title>Todolist React</title>

</head>

<body>

<div id="content"></div>

<script src="build/react.js"></script>

<script src="build/JSXtransformer.js"></script>

<script type="text/jsx" src="src/todolist.js"></script>

</body>

</html>

HTML yang dibuat cukup standar. Sekarang kita akan membuat file javascript

yang dibutuhkan, yaitu src/todolist.js:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

var TodoForm = React.createClass({

render: function () {

return (

<div className="todoForm">

<label htmlFor="todoInput">

Tambahkan Data:

</label>

<input type="text" id="todoInput" className="inputForm" />

</div>

);

}

});

React.render(

<TodoForm />,

document.getElementById("content")

);

Page 85: Java Script Lanjutan

Jalankan kode dan lihat apa yang kita dapatkan:

Apa yang baru saja terjadi?

Pertama, kita membuat sebuah komponen baru di dalam ReactJS dengan

menggunakan method React.createClass.Method ini menerima sebuah parameter

berupa objek yang dapat memiliki banyak method. Untuk contoh awal ini, kita

hanya mengirimkan satu buah method: render. render merupakan method yang

mengembalikan komponen React yang nantinya akan diubah menjadi HTML.

Elemen <div className="todoForm"> yang kita kembalikan bukan merupakan elemen

DOM murni yang dikenali langsung oleh browser. Sebagai kode JSX, kita dapat

menganggap elemen ini merupakan elemen DOM khusus milik React, yang nantinya

akan diterjemahkan menjadi HTML. Perhatikan bagaimana untuk menambahkan kelas

pada elemen kita menggunakan atribut className, bukan class seperti pada HTML

Page 86: Java Script Lanjutan

standar. Hasil kembalian fungsi ini akan diubah menjadi HTML

oleh React.render pada waktunya, dan hasil keluaran HTML ini relatif aman.

React tidak menghasilkan string HTML sehingga kita terlindungi dari serangan

XSS.

Setiap kali kita telah membuat komponen baru melalui React.createClass, kita

kemudian dapat menyimpan komponen ini ke dalam sebuah variabel. Nama dari

variabel ini kemudian akan menjadi komponen baru dari React, yang dapat

digunakan sebagai markup buatan sendiri dalam JSX. Karena hal ini lah kita

dapat langsung mengirimkan komponen yang baru kita buat

sebagai <TodoForm /> ke React.render. Kita bahkan dapat

menggunakan <TodoForm /> di dalam nilai kembalian komponen lainnya.

Untuk mengirimkan data ke dalam komponen React, kita juga dapat menambahkan

atribut ke dalam elemen yang baru saja kita buat. Atribut ini dapat diisikan

dengan nama apapun, selama tidak bertabrakan dengan atribut standar HTML.

Pengisian atribut ke dalam elemen dilakukan dengan mengguankan pemisah {},

seperti berikut:

1

2

3

4

5

6

var judul = "Tambahkan Data";

React.render(

<TodoForm teks={judul} />,

document.getElementById("content")

);

Kita kemudian dapat mengakses nilai atribut ini dengan menggunakan

properti props pada objek yang dikirimkan keReact.createClass:

1

2

3

4

5

6

7

8

9

10

var TodoForm = React.createClass({

render: function () {

return (

<div className="todoForm">

<label htmlFor="todoInput">

{ this.props.teks }

</label>

<input type="text" id="todoInput" className="inputForm" />

</div>

Page 87: Java Script Lanjutan

11

12

);

}

});

Penggabungan beberapa komponen dalam React juga dilakukan dengan cukup

natural: hanya dengan menggunakan komponen-komponen yang telah kita

kembangkan layaknya sebuah tag HTML biasa. Pertama, mari kita buat komponen

baru untuk menampung semua data yang ada:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

// data boleh berasal dari mana saja.

// asumsikan data sudah didapatkan.

var data = [

{content: "Beli Telur", tag: "belanja"},

{content: "Tugas Javascript", tag: "kuliah"},

{content: "This War of Mine", tag: "game"},

{content: "Doraemon", tag: "film"}

];

var List = React.createClass({

render: function () {

var listData = this.props.data.map(function (data) {

return (

<li>{data.content}, tag: {data.tag}</li>

);

});

return (

<ul className="list">

{listData}

</ul>

);

}

});

Page 88: Java Script Lanjutan

Elemen List yang kita kembangkan melakukan sesuatu yang menarik. Data yang

kita peroleh, berupa array dari objek, dipetakan menjadi array dari

elemen <li> JSX pada variabel listData. listData kemudian langsung kita

masukkan sebagai nilai literal di dalam <ul> yang dikembalikan, dan React

secara otomatis mengetahui apa yang harus dilakukan dengan array <li>!

Penggabungan List dan TodoForm dapat dilakukan dengan cukup alami:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var TodoList = React.createClass({

render: function () {

return (

<div className="TodoList">

<h1>Todo List</h1>

<TodoForm teks="Tambahkan Data : " />

<List data={this.props.data} />

</div>

);

}

});

React.render(

<TodoList data={data} />,

document.getElementById("content")

);

Perlu dicatat bahwa sebuah elemen yang dikembalikan oleh komponen React hanya

boleh terdiri dari satu elemen terluar. Hal ini berarti kode berikut:

1

2

3

4

5

6

7

8

var TodoList = React.createClass({

render: function () {

return (

<TodoForm teks="Tambahkan Data : " />

<List data={this.props.data} />

);

}

Page 89: Java Script Lanjutan

});

Tidak akan dapat berjalan dan memberikan kesalahan kompilasi. Untuk

menanggulangi hal ini pastikan untuk selalu membuat elemen pembungkus agar

hanya terdapat satu elemen terluar saja.

Mengambil Data Dari Server

Aplikasi web umumnya tentunya tidak menyimpan data di dalam array secara

lokal seperti contoh pada bagian sebelumnya. Yang biasanya terjadi adalah

pengambilan data dilakukan melalui sisi server. Untuk dapat melakukan hal

ini, kita akan melakukan dua hal. Pertama, pada todo.html kita akan

menambahkan jQuery:

1

2

3

4

5

<head>

<script src="build/jquery-2.1.1.min.js"></script>

<script src="build/react.js"></script>

<script src="build/JSXTransformer.js"></script>

</head>

Kita kemudian perlu membuat file data.json yang isinya tidak berbeda jauh

dengan variabel data yang kita buat sebelumnya:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

[

{

"content": "Beli Telur",

"tag": "belanja"

},

{

"content": "Tugas Javascript",

"tag": "kuliah"

},

{

"content": "This War of Mine",

"tag": "game"

},

Page 90: Java Script Lanjutan

15

16

17

18

{

"content": "Doraemon",

"tag": "film"

}

]

Data pada data.json ini nantinya yang akan kita ambil dari sever.

Selanjutnya, kita tidak akan langsung menggunakan variabel data lagi untuk

mengisikan list. Kita akan mengirimkan URL data yang diperlukan saja.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var TodoList = React.createClass({

render: function () {

return (

<div className="TodoList">

<h1>Todo List</h1>

<TodoForm teks="Tambahkan Data : " />

<List url={this.props.url} />

</div>

);

}

});

React.render(

<TodoList url="./data.json" />,

document.getElementById("content")

);

Selanjutnya, kita perlu memperbaharui komponen List seperti berikut:

1

2

3

4

5

6

var List = React.createClass({

loadData: function () {

$.ajax({

url: this.props.url,

dataType: 'json',

Page 91: Java Script Lanjutan

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

success: function (data) {

this.setState({data: data})

}.bind(this),

error: function (xhr, status, err) {

console.log(xhr);

console.log(status);

console.log(err);

}.bind(this)

});

},

getInitialState: function () {

return { data: [] }

},

componentDidMount: function () {

this.loadData();

},

render: function () {

var listData = this.state.data.map(function (data) {

return (

<li>{data.content}, tag: {data.tag}</li>

);

});

return (

<ul className="list">

{listData}

</ul>

);

}

});

Terdapat beberapa method tambahan yang digunakan di sini.

Pertama, method loadData merupakan method buatan kita untuk mengambil data

Page 92: Java Script Lanjutan

dari server. loadData cukup sederhana, hanya melakukan pengambilan data

melalui fungsi$.ajax dari jQuery.

Pada aplikasi kita sejauh ini, setiap komponen yang kita kembangkan

menampilkan dirinya berdasarkan props yang kita kirimkan. Nilai props tidak

dapat berubah isinya. props dikirimkan oleh komponen teratas, dan “dimiliki”

oleh komponen tersebut. Karena hanya dikirimkan kepada objek, maka

nilai props tidak dapat diubah. Jika ingin mengubah data untuk mendapatkan

interaktifitas aplikasi, kita perlu menggunakan mekanisme khusus yang

disediakan React.this.state merupakan komponen privat yang dapat diganti

isinya dengan memanggil this.setState. Ketika nilaistate diperbaharui,

komponen React akan secara otomatis diperbaharui juga

(fungsi render dipanggil kembali).

Fungsi render sendiri dituliskan sebagai fungsi deklaratif

milik this.props dan this.state. Hal ini menjadikan komponen antarmuka selalu

konsisten dengan interaksi pengguna.

Data dari this.state sendiri kita inisialisasi melalui

fungsi getInitialState. Nilai yang dikembalikan getInitialStateakan menjadi

nilai awal dari this.state. Fungsi ini dijamin oleh React hanya akan berjalan

sekali selama masa hidup komponen.

Method componentDidMount dipanggil secara otomatis oleh React ketika komponen

digambarkan. Kita memanggilthis.setState di sini agar data diperbaharui

secara dinamis. Array data yang lama kita gantikan dengan data yang diambil

dari server, dan komponen (UI) akan secara otomatis memperbaharui dirinya

sendiri. Karena ini, kita dapat dengan mudah mengimplementasikan live update,

dengan teknik polling:

1

2

3

4

componentDidMount: function () {

this.loadData();

setInterval(this.loadData, 2000);

},

Tentu saja kita dapat mengimplementasikan metode live update yang lebih baik,

misalnya dengan menggunakan WebSocket di bagian ini.