Bagaimana Javascript Menghandle Proses Asynchronous - Callback, Promise, Coroutine, dan Async/Await

Javascript adalah bahasa pemrograman yang synchronous by default. Walaupun begitu, pada Javascript Server Side (NodeJS) terdapat beberapa operasi yang asynchronous. Berikut pembahasan tentang bagaimana cara Javascript menghandle ke-asynchronous-annya tersebut

Wahyudi Wibowo
Jul 11, 2017 · 7 min read

Kalau sebelumnya kita sudah membahas Javascript sebagai prototype-based language, kali ini kita akan membahas Javascript dari sisi asynchronousnya.
Javascript atau NodeJS dikenal sebagai bahasa yang single-threaded, non-blocking. Konsekuensi dari non-blocking adalah beberapa operasi yang ada di Javascript merupakan operasi yang asynchronous, seperti akses ke database, membuka file, atau melakukan request http via AJAX.

Saat awal-awal belajar Javascript dulu, saya yang berasal dari background bahasa pemrograman yang blocking, sempat dibuat bingung oleh Javascript karena kode yang dieksekusi tidak sesuai dengan alur penulisannya. Mari kita lihat contoh kode di bawah ini:

Secara naluri, saya mengira bahwa console.log(content); akan berisi konten dari text.txt , namun yang terjadi console.log(content) ternyata mengembalikan nilai undefined . Kenapa bisa begitu ? Disini saya akan jelaskan poin pentingnya

Di Javascript, ada 2 macam operasi yaitu operasi yang synchronous dan asynchronous. Definisi synchronous adalah sebuah operasi akan dijalankan setelah operasi sebelumnya selesai dijalankan alias berurutan. Sedangkan asynchronous sebaliknya, asynchronous tidak perlu menunggu operasi sebelumnya selesai untuk mengeksekusi operasi setelahnya. Sebagian besar eksekusi di Javascript itu synchronous, namun beberapa operasi seperti akses ke database, akses ke file, atau melakukan AJAX call adalah operasi yang asynchronous. Pada contoh diatas, kita melakukan akses membaca file yang merupakan operasi yang asynchronous, sehingga ketika compiler mulai membaca file, compiler tidak menunggu sampai file itu selesai dibaca, melainkan langsung mengeksekusi kode setelahnya. Sehingga console.log(content); akan mengembalikan nilai undefined karena pada saat file text.txt mulai dibaca, Javascript langsung mengeksekusi console.log(content); yang pada saat itu nilainya memang masih undefined. Ketika content = data; selesai dilakukan, compiler menganggap semua baris kode sudah selesai dieksekusi, sehingga tidak melakukan apapun lagi.

Lalu bagaimana cara kita meng-handle hasil dari operasi yang asynchronous tersebut ? Pada saat Javascript masih dikenal sebagai script untuk frontend, kita mengenal event seperti onload, onclick , onhover dan sebagainya. Namun ketika kita menggunakan Javascript di sisi backend, tentu penggunaan event tidak efektif karena kita harus mendefinisikan event untuk tiap-tiap operasi yang asynchronous. Sebagai server side language, ada beberapa cara bagi Javascript untuk menghandle return value dari operasi yang asynchronous tersebut. Kita dapat menggunakan callback, promise, coroutine, dan async/await.

Callback

Callback function atau callback (biasa disingkat dengan cb) adalah salah satu metode yang paling umum yang digunakan untuk menghandle return value dari operasi asynchoronous. Konsep callback dapat dianalogikan seperti kita memanggil penjual untuk membeli sesuatu dan sembari menunggu penjual mempersiapkan barangnya, kita pergi melakukan hal lain. Lalu, ketika barangnya sudah siap, penjual akan memanggil balik (callback) untuk memberitahu kita bahwa barang sudah siap dan kita dapat menentukan tindakan selanjutnya dari pembelian barang tadi.

Callback sendiri adalah sebuah regular function (yang biasanya anonymous) dan ditaruh di argumen paling belakang dari sebuah asynchronous function. Layaknya function biasa, callback juga dapat menerima parameter dan mengembalikan value. Berikut adalah contoh pengaplikasian callback.

Dan hasilnya jika di-run:

See ? kita bisa melihat proses asynchronous yang terjadi dimana console.log() yang ada di baris paling bawah dieksekusi tanpa menunggu asyncDivision selesai.

Sekarang mari kita lihat anonymous function yang terletak di argumen paling belakang pada implementasi function asyncDivision. Itulah yang kita sebut dengan callback yang berfungsi sebagai handler ketika operasi asynchronous selesai dijalankan. Pada contoh diatas saya menggunakan NodeJS style callback, dimana parameter pertama callback direserved untuk error, dan parameter kedua direserved untuk result.

Penggunaan callback ini memiliki kelemahan yaitu return value dari callback hanya dapat dipanggil di dalam callback function tersebut, hal ini mengundang para developer untuk menulis kode dengan struktur nested sehingga menyebabkan hal yang disebut dengan callback hell.

Struktur seperti ini tentu sulit dibaca jika codebase semakin berkembang. Next, kita akan melihat cara lain untuk menghandle proses asynchronous yang kodenya lebih readable daripada callback.

Promise

Promise hadir secara native di Javascript semenjak ES6. Promise, seperti namanya merupakan janji atau kontrak. Analoginya sama seperti pembelian barang tadi, bedanya adalah pembeli sudah menyiapkan kontrak yang berlaku apabila barang sudah siap. Kontrak tersebut berisi ketentuan yang yang mengatur apa yang harus dilakukan apabila kondisi terpenuhi (resolved) atau tertolak (rejected). Cara kerja Promise kurang lebih seperti ini :

Oke, biar lebih jelas let’s jump straight to the code! Agar lebih mudah dipahami, saya akan menggunakan kode callbackHell.js yang diubah menjadi bentuk promise.

dan jika di-run maka hasilnya :

Implementasi promise berbentuk seperti chain atau rantai, yang lebih mudah untuk dibaca daripada struktur nested yang dimiliki oleh callback. Namun promise juga memiliki beberapa aturan, antara lain :

  1. Scope variable yang ada di dalam sebuah block .then() tidak dapat diakses diluar block tersebut (lihat kode yang dicomment pada contoh di atas).
  2. Promise hanya dapat mengembalikan 1 return value. Kita tidak dapat mengembalikan multiple return value seperti ini resolve(a, b) ;
  3. Promise bersifat fail fast yang artinya jika ada satu promise yang di-reject, maka akan langsung dilempar ke block .catch() tanpa mengeksekui rantai .then dibawahnya.

Lagi-lagi, karena aturan yang dimiliki promise, banyak developer yang menyalahgunakan promise ini sehingga memiliki struktur nested yang disebut promise pyramid of doom yang kurang lebih sama dengan callback hell. Mari kita lihat contohnya :

Pada contoh di atas, promise sendBookingConfirmation berada di dalam .then -nya promise .create. Begitu pula dengan promise statistics yang berada di dalam then -nya promise sendBookingConfirmation. Hal ini dilakukan semata-mata karena variable data scopenya terbatas, padahal data masih akan digunakan di promise-promise selanjutnya. Sehingga terciptalah promise di dalam promise di dalam promise.

Walaupun memiliki kelemahan, tapi promise telah menawarkan solusi yang lebih baik dari callback. Belum lagi fungsi bawaan dari promise seperti Promise.resolve , Promise.reject , dan Promise.all yang mempermudah kita untuk aggregasi proses asynchronous. Ada juga library seperti Bluebird yang meng-extend promise bawaan Javascript menjadi lebih powerful.

Coroutine

Baik callback dan promise sama-sama menawarkan solusi untuk menghandle proses asynchronous, tapi cara penulisan kodenya masih terasa aneh. Adakah cara untuk menghandle proses asynchronous yang terasa seperti menulis kode yang synchronous ?

Semenjak adanya generator function di ES6, beberapa orang menyadari bahwa generator berpotensi untuk menghandle proses asynchronous. Generator adalah sebuah function, namun tidak seperti function pada umumnya, menjalankan kode tidak sekali jalan sampai selesai, melainkan dapat di pause, lalu dijalankan lagi. Generator juga berjalan secara synchronous. Fitur run pause run yang synchronous ini dirasa cocok apabila dipadukan dengan promise untuk “menyembunyikan” proses asynchronous sehingga terlihat synchronous.

Generator + Promise = Coroutine

Sekarang, mari kita coba implementasi coroutine dengan contoh kode yang sama dengan sebelumnya :

Disini saya menggunakan 2 library sebagai perbandingan : tj/co dan bluebird Promise.coroutine . Dari contoh di atas kita bisa lihat bahwa penulisan kode yang asynchronous menjadi serupa dengan kode yang synchronous hanya dengan cara menuliskan kode di dalam coroutine wrapper dan menambahkan yield setelah promise. Dan jangan lupa bahwa coroutine wrapper membutuhkan generator sebagai parameternya (function* menandakan bahwa fungsi tersebut adalah generator). Mudah bukan ?

Perbedaan dari 2 library yang saya pakai terletak dieksekusinya. Jika kita memakai co , kode akan langsung dieksekusi. Sedangkan di Promise.coroutine, coroutine dapat disimpan di variable dan dieksekusi sesuai kemauan pengguna. Library co juga memiliki fitur yang sama dengan Promise.coroutine yang mengeksekusi coroutinenya sesuai kemauan pengguna, yaitu dengan menggunakan co.wrap.

Async/Await

Terakhir adalah async/await. Salah satu fitur yang paling ditunggu-tunggu oleh developer Javascript. async/await merupakan “coroutine” yang native alias bawaan dari Javascript. async/await sendiri dapat digunakan secara native jika kita menggunakan Node mulai dari versi 7.6. Untuk versi dibawah itu, kita harus menggunakan babel untuk menerjemahkan sintaks async/await ke sintaks yang dimengerti oleh Node.

Sekarang, mari kita tuliskan contoh kode di atas, namun dengan versi async/await. Note : untuk menjalankan kode di bawah ini memerlukan Node ≥ 7.6

Penggunaan async/await hampir sama dengan Promise.coroutine bukan ? tidak hanya itu, tapi kita dapat menggunakan good ol’ try catch untuk menghandle error di async/await . Mari kita hapus line 38 sampai akhir dan kita ganti dengan kode di bawah ini :

Yang perlu kita ingat adalah jangan menggunakan try catch dan .then() .catch() secara bersamaan untuk menghindari efek yang tidak diinginkan.

Demikian penjelasan tentang bagaimana cara Javascript menghandle proses asynchronousnya. Semoga artikel ini dapat memberikan pencerahan. Jika ada pertanyaan, saran, dan masukan, please leave a comment below 😄


Terimakasih telah membaca artikel ini. Apabila anda menyukainya klik ❤️ dan share serta follow medium, facebook, atau twitter Koding Kala Weekend untuk mendapat info tentang artikel terbaru kami.

Koding Kala Weekend

Belajar pemrograman di akhir pekan

Wahyudi Wibowo

Written by

Dad | Backend Dev : PHP, NodeJS, Go | Lifelong learner | Passionate about programming stuff

Koding Kala Weekend

Belajar pemrograman di akhir pekan

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade