
Asynchronous Javascript 2 - Callback
Definisi paling sederhana dan cukup dari fungsi Callback adalah “Sebuah fungsi yang dijadikan argumen untuk fungsi yang lain, yang nantinya akan dipanggil oleh fungsi tersebut untuk menyelesaikan suatu tugas”.
function makeCoffee(callback) {
console.log("brewing delicious coffee...");
callback();
}
function getCoffee() {
console.log("Here is your coffee ☕");
}
makeCoffee(getCoffee);
Pada kode diatas, fungsi getCoffee
dijadikan argumen untuk fungsi makeCoffee
yang akan dipanggil setelah proses tertentu. getCoffee
disini adalah sebuah callback.
Jika sudah cukup lama belajar Javascript, secara tidak sadar kamu pasti sering bersinggungan dengan callback. Saat menggunakan timeout, atau operasi dengan array.
const arr = ["halo", "darkness"];
function callback(str) {
return str.toUpperCase();
}
const capitalized = arr.map(callback);
// setTimeout
function callback2() {
console.log(capitalized);
}
setTimeout(callback2, 100); // ['HALO', 'DARKNESS']
Synchronous vs Asynchronous Callback
Callback bisa dipanggil secara synchronous maupun asynchronous , dan membedakan keduanya penting ketika menganalisa side-effects (akibat sebuah proses yang merubah suatu keadaan, seperti merubah value variabel) dari suatu kode yang dieksekusi. Perhatikan kode berikut
apabila Callback dari suatuFungsi
dipanggil secara synchronous, maka output dari num adalah 2
tapi jika asynchronous, maka hasilnya adalah 1
, karena variabel num
belum memiliki nilai yang baru.
Callback untuk Event listener
Event listener yang biasa digunakan untuk “mendengar” segala hal yang terjadi di DOM, juga menerima suatu Callback untuk dipanggil ketika suatu “Event” berjalan. Kode dibawah menampilkan Callback yang dipanggil setiap cursor mouse bergerak.
Callback untuk HTTP request
Salah satu proses yang tidak tentu waktu eksekusinnya adalah HTTP request, yaitu proses interaksi dengan server yang dilakukan oleh client (misal browser) untuk mendapatkan atau mengirim data.
Berikut adalah contoh kode penggunaan AJAX untuk melakukan HTTP request ke fake API service jsonplaceholder.
Pada kode di atas, fungsi getData
akan melakukan permintaan ke API untuk mendapatkan data pengguna. Fungsi getData
memiliki dua parameter, yaitu url
untuk URL API dan callback
yang akan dipanggil dengan hasil data sukses ataupun error.
- Parameter
url
adalah URL endpoint yang akan diakses. - Parameter
callback
adalah fungsi yang akan dieksekusi setelah permintaan selesai. Callback ini memiliki dua argumen:err
untuk error (jika ada), dandata
untuk data yang diterima dari server.
Penggunaan callback dalam menangani operasi asynchronous memiliki kelemahan yaitu potensi terbentuknya callback hell, di mana callback bertumpuk terlalu dalam sehingga kode menjadi sulit dibaca dan dikelola. Untuk mengatasi ini, JavaScript memperkenalkan Promise dan async/await.
Callback hell
Neraka callback adalah suatu kondisi dimana Callback memiliki banyak callback lain didalamnya, saling membungkus satu sama lain, sehingga kode yang ada jadi sulit dibaca dan rentan terhadap bug.
Menggunakan contoh AJAX sebelumnya, bisa dibuat skenario dimana data yang diminta dari server saling terkait sehingga menciptakan neraka callback.
Misalkan untuk mendapatkan data pengguna yang membuat sebuah post dimana pada post tersebut terdapat komentar berisi ujaran kebencian. Maka, tahapan yang perlu dilalui untuk mendapatkan data pengguna tersebut adalah:
- mendapatkan data komentar berisi ujaran kebencian
- mencari data post dengan komentar tersebut
- mendapatkan data pengguna yang membuat post
Berikut adalah kode untuk melakukan tahapan diatas:
Perhatikan penggunaan fungsi getData
yang saling membungkus pada kode diatas. Sekilas melihat saja cukup sulit untuk menangkap proses permintaan dan penampilan data. Kode diatas padahal masih cukup sederhana karena tidak ada manipulasi data atau pengangan error yang serius.
Bayangkan apabila proses permintaan data dari server bukan hanya 3, tapi 5 atau 7, akan sesulit apa me-menej kode nantinya. Maka kondisi ini disebut sebagai neraka callback atau pyramid of doom, piramida kiamat, karena pada sisi kiri kode akan terbentuk piramid yang makin tinggi makin mengerikan.
Bonus: Callback untuk pemrograman yang lebih dinamis
Selain berguna untuk berhadapan dengan situasi asynchronous, callback juga berguna untuk membuat abstraksi yang lebih dinamis. Perhatikan kode berikut
function validateString(str, rules) {
// membersihkan string
const cleanString = str.trim();
// cek apakah string kosong
if (rules === "required") {
if (cleanString.length === 0) {
return false;
}
}
// cek apakah string sepenuhnya alphabet
if (rules === "alphabet") {
if (/^[A-Za-z ]+$/.test(cleanString)) {
return false;
}
}
// cek maksimal karakter
if (rules === "max") {
if (cleanString.length > 10) {
return false;
}
}
// jika semua validasi oke
return true;
}
Kode diatas adalah fungsi sederhana untuk melakukan validasi terhadap karakter pada suatu string. Secara fungsionalitas, fungsi validateString
sudah oke, ia bisa memvalidasi sesuai yang diinginkan. Namun, bagaimana jika inging ditambahkan validasi yang lainnya? jika makin banyak kondisi yang ditambahkan, tentu fungsi akan semakin besar dan monoton.
Dengan callback, kode diatas dapat dibuat jadi lebih dinamis dan meningkatkan readability nya. Lihat modifikasi kode dibawah:
function validateString(str, validator) {
// membersihkan string
const cleanString = str.trim();
// melakukan validasi
return validator(cleanString);
}
function isRequired(str) {
return str.trim().length > 0;
}
function isAlphabetic(str) {
return /^[A-Za-z ]+$/.test(str);
}
function maxLength(str, maxLength) {
return str.length <= maxLength;
}
// penggunaan
validateString("Hello", isRequired);
validateString("Hello", isAlphabetic);
validateString("Hello", (str) => maxLength(str, 5));