Terakhir diperbaharui: Aug 8, 2021
Asynchronous
Daftar Isi
Single Threaded Event Loop Callback JavaScript Promise - Callback vs Promise Async Await - Promise vs Async AwaitProses asynchronous sering digunakan untuk komunikasi data, karena data menjadi bagian inti dari sebuah aplikasi maka konsep asynchronous sangat penting untuk dipahami.
Single Threaded
Selain termasuk Interpreted Language dan Dynamic-Typed Language, JavaScript juga termasuk Single Threaded Programming Language.
Yaitu JavaScript hanya bisa melakukan satu operasi di satu waktu, sehingga code JavaScript dieksekusi secara berurutan dari atas ke bawah layaknya sebuah antrian atau biasa disebut synchronous.
1console.log('Hi Brachio');23console.log('the time has come');45console.log('to learn how to code');
Namun hal ini bisa menjadi masalah jika terdapat code yang eksekusinya membutuhkan waktu yang lama, seperti code untuk mendownload data dari server.
Kita tidak tahu berapa lama waktu yang dibutuhkan untuk download data tersebut.
Jika mengikuti mekanisme synchronous dimana JavaScript hanya bisa melakukan satu operasi di satu waktu maka seharusnya JavaScript akan berhenti dan tidak akan mengeksekusi code selanjutnya sebelum download selesai.
Kenyataannya kita masih bisa melakukan aktifitas browsing meskipun download sedang berlangsung dan browser tidak hang.
Bagaimana JavaScript bisa melakukannya?
Jawabannya adalah JavaScript melakukannya secara asynchronous.
Pada konsep asynchronous, code akan dieksekusi tanpa menunggu eksekusi code lain selesai sehingga seakan-akan dieksekusi secara bersamaan.
Kita bisa menggunakan simulasi berikut:
1console.log('Hi Brachio');23setTimeout(function () {4 console.log('the time has come');5}, 3000);67console.log('to learn how to code');
setTimeout pada code di atas membuat kata the time has come akan ditampilkan setelah 3 detik.
Namun JavaScript tidak akan menunggu selama 3 detik tapi akan segera menampilkan kata to learn how to code.
Sehingga hasilnya:
1Hi Brachio2to learn how to code3the time has come
Berikut gambaran perbedaan antara synchronous, asynchronous, dan asynchronous pada javascript:
Synchronous
Asynchronous
Asynchronous pada JavaScript
Event Loop
Untuk lebih memahami asynchronous pada JavaScript kita perlu mengetahui apa itu Event Loop.
Event loop adalah bagian dari JavaScript Runtime yang bertugas untuk menangani Event Callback, Event Callback sendiri adalah bagian dari code yang dieksekusi setelah event tertentu.
Contoh Kasus: Klik tombol Download di browser.
- mouse click adalah event
- function yang bertugas untuk mengunduh adalah callback
Ketika event terjadi maka callback dari event tersebut akan ditempatkan pada suatu tempat yang disebut Event Handler Queue atau Queue.
Event Loop akan terus memonitor Queue dan akan mengeksekusi callback sesuai urutan siapa yang pertama masuk ke dalam Queue.
Ada 3 teknik yang digunakan untuk menghandle proses asynchronous pada JavaScript:
Callback JavaScript
Callback adalah function yang menjadi argument untuk function lain dan akan dieksekusi pada poin tertentu, bisa jadi saat ini atau nanti.
Contoh
1const notify = () => {2 console.log('Download complete!');3};45const download = (url, callback) => {6 console.log(`Downloading from ${url}....`);78 callback();9};1011const url = 'https://brachio.site/download';1213download(url, notify);
Output dari code di atas adalah:
1Downloading from https://brachio.site/download....2Download complete!
Pada code di atas function notify adalah callback function, dipanggil setelah code console.log(Downloading from \${url}....);.
💡 INFO
Menjadikan function sebagai argument untuk function yang lain adalah sesuatu yang mungkin di JavaScript, karena function pada JavaScript adalah First-Class Object.
Yang berarti function memiliki karakter yang sama dengan object.
Sehingga sebuah function dapat:
- disimpan dalam sebuah variable, object atau array
- menjadi argument untuk function lain (High-Order Function)
- menghasilkan function baru
Nested Callback
Kita bisa menambahkan callback di dalam callback.
1const download = (url, callback) => {2 console.log(`Downloading from ${url}....`);34 callback();5};67const url1 = 'https://brachio.site/download';8const url2 = 'https://trex.site/download';9const url3 = 'https://stego.site/download';1011download(url1, function () {12 download(url2, function () {13 download(url3, function () {14 console.log('Download complete!');15 });16 });17});
Code di atas dieksekusi tanpa error dan menghasilkan ouput yang sesuai dengan perkiraan.
1Downloading from https://brachio.site/download....2Downloading from https://trex.site/download....3Downloading from https://stego.site/download....4Download complete!
Namun kondisi ini bisa mengarah ke suatu masalah yang disebut dengan Callback Hell, yaitu kondisi dimana terlalu banyak callback di dalam callback yang lain.
Callback Hell membuat code sulit untuk dipahami dan sulit diperbaiki jika ditemukan bug di dalamnya.
Sebagai gantinya kita bisa menggunakan Promise.
Promise
Promise bisa dikatakan sebagai object yang menyimpan hasil dari sebuah operasi asynchronous baik itu hasil yang diinginkan (resolved value) atau alasan kenapa operasi itu gagal (failure reason).
Kita ambil contoh seperti saat kita memesan ojek online.
Saat kita mencari driver lewat aplikasi, aplikasi akan berjanji(promise) memberi tahu hasil dari pencarian kita.
Hasilnya bisa diantara dua, yaitu driver ditemukan (resolved value) atau alasan kenapa driver tidak ditemukan(failure reason).
Sebuah Promise berada di salah satu diantara 3 kondisi(state):
- pending, operasi sedang berlangsung
- fulfilled, operasi selesai dan berhasil
- rejected, operasi selesai namun gagal
Sama seperti pada kasus memesan ojek online, status permintaan kita pada aplikasi online diantara tiga kondisi:
- Mencari driver (pending)
- Menemukan driver (fulfilled)
- Driver tidak ditemukan (rejected)
Membuat Promise
Keyword yang dipakai untuk membuat Promise adalah Promise.
1let progress = 100;23const download = new Promise((resolve, reject) => {4 if (progress === 100) {5 resolve('Download complete');6 } else {7 reject('Download failed');8 }9});
Function setelah keyword new Promise disebut executor.
Dan di dalam executor terdapat dua callback function:
- resolve(value) adalah callback function yang dieksekusi jika operasi yang dijalankan oleh executor berhasil(fulfilled)
- reject(error) adalah callback function yang akan dieksekusi jika operasi gagal (rejected)
Promise Handler
Selanjutnya untuk merespon hasilnya (baik berupa value atau error) kita perlu menambahkan handler.
Handler biasanya berupa function dan ditempatkan di dalam method bernama then().
1download.then((result, error) => {2 console.log(result); // Download complete3 console.log(error); // Download failed atau undefined jika tidak ada error4});
sedangkan untuk merespon error kita bisa tambahkan method catch().
1download2 .then((result) => {3 console.log(result); // Download complete4 })5 .catch((error) => {6 console.log(error); // Download failed atau tidak ditampilkan jika tidak ada error7 });
Promise Chaining
Karena output dari method then() dan catch() adalah sebuah Promise, maka kita bisa merangkainya(chain) dengan Promise yang lain.
1let initProgress = 0;23const download = new Promise((resolve, reject) => {4 let progress = initProgress + 25;5 resolve(progress);6});78download9 .then((result) => {10 console.log(`Download progress is ${result}%`);11 return result + 25;12 })13 .then((result) => {14 console.log(`Download progress is ${result}%`);15 return result + 50;16 })17 .then((result) => {18 if (result === 100) {19 console.log('Download complete');20 }21 });
Promise.all()
Method Promise.all() digunakan untuk mengeksekusi Promise secara paralel.
Output dari Promise.all() adalah sebuah promise.
1const downloadStart = new Promise((resolve, reject) => {2 resolve('0%');3});4const downloadHalf = new Promise((resolve, reject) => {5 resolve('50%');6});7const downloadFull = new Promise((resolve, reject) => {8 resolve('100%');9});1011Promise.all([downloadStart, downloadHalf, downloadFull]).then((result) => {12 console.log(result); // [ '0%', '50%', '100%' ]13});
Callback vs Promise
Seperti yang disebutkan sebelumnya bahwa kita bisa menggunakan promise untuk mengatasi masalah callback hell.
❌ Callback Hell
1const download = (url, callback) => {2 console.log(`Downloading from ${url}....`);34 callback();5};67const url1 = 'https://brachio.site/download';8const url2 = 'https://trex.site/download';9const url3 = 'https://stego.site/download';1011download(url1, function () {12 download(url2, function () {13 download(url3, function () {14 console.log('Download complete!');15 });16 });17});
✔️ Promise
1const download = (url) => {2 return new Promise((resolve, reject) => {3 resolve(`Downloading from ${url}....`);4 });5};67const url1 = 'https://brachio.site/download';8const url2 = 'https://trex.site/download';9const url3 = 'https://stego.site/download';1011Promise.all([download(url1), download(url2), download(url3)]).then((result) => {12 for (let downloadInfo of result) {13 console.log(downloadInfo);14 }15 console.log('Download Complete');16});
💡 Callback adalah function dan Promise adalah object
Async Await
Async/Await diperkenalkan di ES8 / ES2017 untuk menghandle operasi asynchronous dengan syntax yang lebih mirip dengan synchronous.
Async/Await sendiri dibuat di atas Promise.
Kita bisa membuat simulasi proses download menggunakan code dibawah ini.
1const getStatus = (url) => {2 console.log(`Downloading from ${url}...`);34 return new Promise((resolve, reject) => {5 setTimeout(() => {6 resolve('Download Complete');7 }, 3000);8 });9};1011async function download(url) {12 let status = await getStatus(url); // tunggu sampai promise selesai13 console.log(status);14}1516const url = 'https://brachio.site/download';1718download(url);
Pada code di atas keyword await membuat function download harus menunggu sampai function getStatus() selesai dieksekusi.
❗ Keyword
await
harus berada di dalam function async
Promise vs Async Await
Sekarang mari kita update code sebelumnya yang menggunakan Promise menjadi menggunakan Async/Await.
Promise
1const download = (url) => {2 return new Promise((resolve, reject) => {3 resolve(`Downloading from ${url}....`);4 });5};67const url1 = 'https://brachio.site/download';8const url2 = 'https://trex.site/download';9const url3 = 'https://stego.site/download';1011Promise.all([download(url1), download(url2), download(url3)]).then((result) => {12 for (let downloadInfo of result) {13 console.log(downloadInfo);14 }15 console.log('Download Complete');16});
Async/Await
1const download = (url) => {2 return new Promise((resolve, reject) => {3 resolve(`Downloading from ${url}....`);4 });5};67const url1 = 'https://brachio.site/download';8const url2 = 'https://trex.site/download';9const url3 = 'https://stego.site/download';1011async function runDownload() {12 let result1 = await download(url1);13 console.log(result1);1415 let result2 = await download(url2);16 console.log(result2);1718 let result3 = await download(url3);19 console.log(result3);2021 console.log('Download Complete');22}2324// run async function25runDownload();
Kita juga bisa menggunakan arrow function.
1const download = (url) => {2 return new Promise((resolve, reject) => {3 resolve(`Downloading from ${url}....`);4 });5};67const url1 = 'https://brachio.site/download';8const url2 = 'https://trex.site/download';9const url3 = 'https://stego.site/download';1011const runDownload = async () => {12 let result1 = await download(url1);13 console.log(result1);1415 let result2 = await download(url2);16 console.log(result2);1718 let result3 = await download(url3);19 console.log(result3);2021 console.log('Download Complete');22};2324// run async function25runDownload();