Search by

    Terakhir diperbaharui: Aug 8, 2021

    Asynchronous

    Proses 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');
    2
    3console.log('the time has come');
    4
    5console.log('to learn how to code');

    synchronous

    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.

    browser synchronous

    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');
    2
    3setTimeout(function () {
    4 console.log('the time has come');
    5}, 3000);
    6
    7console.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 Brachio
    2to learn how to code
    3the time has come

    Berikut gambaran perbedaan antara synchronous, asynchronous, dan asynchronous pada javascript:

    Synchronous

    normal synchronous

    Asynchronous

    normal asynchronous

    Asynchronous pada JavaScript

    js asynchronous

    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.

    event loop

    Ada 3 teknik yang digunakan untuk menghandle proses asynchronous pada JavaScript:

    1. Callback
    2. Promise
    3. Async Await

    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};
    4
    5const download = (url, callback) => {
    6 console.log(`Downloading from ${url}....`);
    7
    8 callback();
    9};
    10
    11const url = 'https://brachio.site/download';
    12
    13download(url, notify);

    callback

    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}....`);
    3
    4 callback();
    5};
    6
    7const url1 = 'https://brachio.site/download';
    8const url2 = 'https://trex.site/download';
    9const url3 = 'https://stego.site/download';
    10
    11download(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;
    2
    3const 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 complete
    3 console.log(error); // Download failed atau undefined jika tidak ada error
    4});

    sedangkan untuk merespon error kita bisa tambahkan method catch().

    1download
    2 .then((result) => {
    3 console.log(result); // Download complete
    4 })
    5 .catch((error) => {
    6 console.log(error); // Download failed atau tidak ditampilkan jika tidak ada error
    7 });

    Promise Chaining

    Karena output dari method then() dan catch() adalah sebuah Promise, maka kita bisa merangkainya(chain) dengan Promise yang lain.

    1let initProgress = 0;
    2
    3const download = new Promise((resolve, reject) => {
    4 let progress = initProgress + 25;
    5 resolve(progress);
    6});
    7
    8download
    9 .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});
    10
    11Promise.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}....`);
    3
    4 callback();
    5};
    6
    7const url1 = 'https://brachio.site/download';
    8const url2 = 'https://trex.site/download';
    9const url3 = 'https://stego.site/download';
    10
    11download(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};
    6
    7const url1 = 'https://brachio.site/download';
    8const url2 = 'https://trex.site/download';
    9const url3 = 'https://stego.site/download';
    10
    11Promise.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}...`);
    3
    4 return new Promise((resolve, reject) => {
    5 setTimeout(() => {
    6 resolve('Download Complete');
    7 }, 3000);
    8 });
    9};
    10
    11async function download(url) {
    12 let status = await getStatus(url); // tunggu sampai promise selesai
    13 console.log(status);
    14}
    15
    16const url = 'https://brachio.site/download';
    17
    18download(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};
    6
    7const url1 = 'https://brachio.site/download';
    8const url2 = 'https://trex.site/download';
    9const url3 = 'https://stego.site/download';
    10
    11Promise.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};
    6
    7const url1 = 'https://brachio.site/download';
    8const url2 = 'https://trex.site/download';
    9const url3 = 'https://stego.site/download';
    10
    11async function runDownload() {
    12 let result1 = await download(url1);
    13 console.log(result1);
    14
    15 let result2 = await download(url2);
    16 console.log(result2);
    17
    18 let result3 = await download(url3);
    19 console.log(result3);
    20
    21 console.log('Download Complete');
    22}
    23
    24// run async function
    25runDownload();

    Kita juga bisa menggunakan arrow function.

    1const download = (url) => {
    2 return new Promise((resolve, reject) => {
    3 resolve(`Downloading from ${url}....`);
    4 });
    5};
    6
    7const url1 = 'https://brachio.site/download';
    8const url2 = 'https://trex.site/download';
    9const url3 = 'https://stego.site/download';
    10
    11const runDownload = async () => {
    12 let result1 = await download(url1);
    13 console.log(result1);
    14
    15 let result2 = await download(url2);
    16 console.log(result2);
    17
    18 let result3 = await download(url3);
    19 console.log(result3);
    20
    21 console.log('Download Complete');
    22};
    23
    24// run async function
    25runDownload();