PROA

Professional Academy

JavaScript - Callback

Agenda

  • Review Closures
  • Fungsi sebagai First Class Object
  • Intro Callback
  • Nested Callback

Review Closures

Masih ingat tentang closures?

const variabelGlobal = 'global';

const fnLuar = () => {
  const variabelLokal = 'lokal';
  const fnDalam = (paramDalam) => {
    return 'halo ' + variabelLokal + ' ' + paramDalam;
  };
  return fnDalam; // tidak diinvoke
};

const fnKembalian = fnLuar(); // return fnDalam
console.log(fnKembalian('ini untuk dalam')); // invoke fnDalam
console.log(fnKembalian('ini dijagain')); // invoke fnDalam

Kok bisa?

Sebuah fungsi di dalam javascript bisa mengembalikan sebuah fungsi lainnya?

Fungsi sebagai First Class Object

  • Dalam javascript, fungsi adalah first class object, atau objek "kasta atas", artinya:
    • Fungsi bisa dimasukkan ke dalam variabel, object, ataupun array
    • Fungsi bisa dikembalikan (return) oleh fungsi lainnya
    • Fungsi bisa dijadikan sebuah argumen dalam fungsi lainnya

Intro Callback

  • Proses Synchronous dan Asynchronous
  • Apa itu Callback
  • Mari buat Callback

Proses Synchronous dan Asynchronous

Dalam dunia pemrograman, ada 2 cara proses:

  • Synchronous (sync)
  • Asynchronous (async)

Proses Sync dan Async

Sync = eksekusi program yang akan menunggu proses sebelumnya selesai, sebelum prosesnya dijalankan (blocking)
Async = eksekusi program yang dapat berjalan tanpa menunggu proses sebelumnya selesai (non-blocking)

Proses Sync dan Async - Analogi

Analoginya adalah order makanan: Drive-through vs Order restoran

  • Drive-through = dilayani secara berurutan (sequential), selama depan belum selesai, belakang akan menunggu
  • Order restoran = dapur akan buat beberapa bersamaan, tidak menunggu bahkan kadang bisa diserobot urutannya

Proses Sync dan Async - Contoh

(function fnSync() {
  console.log('1');
  console.log('2');
  console.log('3');
})();
(function fnAsync() {
  console.log('A');
  console.log('B');
  // setTimeout adalah fungsi, di dalamnya menerima 
  // sebuah parameter fungsi
  setTimeout(function() {
    console.log('Process C');
  }, 1000);

  console.log('D');
})();

Apakah outputnya?

Loh kok ...
  • bisa ada fungsi dalam fungsi?
  • (tahan dulu yah)yang bawah kenapa hasilnya begitu?

Fungsi sebagai First Class Object (Revisited)

  • Dalam javascript, fungsi adalah first class object, atau objek "kasta atas", artinya:
    • Fungsi bisa dimasukkan ke dalam variabel, object, ataupun array
    • Fungsi bisa dikembalikan (return) oleh fungsi lainnya
    • Fungsi bisa dijadikan sebuah argumen dalam fungsi lainnya

Apa itu Callback

Sebuah fungsi yang dijadikan sebuah argumen pada fungsi lainnya

Contoh Callback

Misalnya saya punya beberapa pekerjaan yang harus dilakukan:

  • Menelpon pasangan karena bucin
  • Mengerjakan tugas tantangan
  • Cuci baju

Contoh Callback (ii)

Kita coba lihat urutan kerjaannya yah:

  • Pada saat menelpon pasangan, ternyata adiknya yang angkat dan mengatakan bahwa si dia sedang mandi, dan saya diminta menunggu (hold) telepon
  • Saya tidak mau, dan titip pesan ke adiknya, kalau si dia udah kelar mandi, tolong kabari si dia untuk telepon ke saya yah
  • Sembari menunggu si dia menelpon balik, saya bisa mengerjakan tantangan atau cuci baju dulu
  • Ketika si dia selesai mandi dan menelepon, saya akan stop kerjaan saya sekarang, dan melepas rindu dengan si dia
  • Ini adalah salah satu contoh callback di dunia nyata

Contoh Callback (iii)

Sedikit Catatan

  • Saya ini orangnya hanya bisa mengerjakan satu pekerjaan dalam satu waktu (single threaded)
  • Saya tidak bisa Kage bunshin no jutsu atau membelah diri untuk mengerjakan banyak hal dalam satu waktu
  • Tapi selagi menunggu pekerjaan yang lain selesai, saya bisa mengerjakan pekerjaan lainnya (async / non-blocking)

Contoh Callback (iv)

Mari kita coba lihat contoh kodenya - tanpa callback

function main() {
  telponDenganSiDia(); 
  // apabila tanpa callback
  // maka ini akan menunggu 30 s.d. 1 jam
  // baru bisa mengerjakan pekerjaan selanjutnya
  mengerjakanTantangan();
  cuciBaju();
}

Contoh Callback (v)

Mari kita coba lihat contoh kodenya - dengan callback

function main() {
  telponDenganSiDia(function siDiaTelponBalik(diaSudahSiap) {
    bucinan(diaSudahSiap);
  });
  mengerjakanTantangan();
  cuciBaju();
}

Kembali ke kode

function fungsiKesatu() {
  console.log('satu');
}

function fungsiKedua() {
  console.log('dua');
}

fungsiKesatu();
fungsiKedua();

Di kode ini, fungsiKesatu akan dijalankan duluan sebelum fungsiKedua

Kembali ke kode (ii)

Mari kita pikirkan suatu hal

  • Apa yang akan terjadi bila si fungsiKesatu memiliki kode yang tidak bisa dijalankan dengan cepat?
  • Misalnya seperti:
    • membaca file yang jumlahnya sangat besar?
    • menunggu data dari tempat lain (api request)?
    • Mari kita coba simulasikan dengan setTimeout (fungsi bawaan javascript)

Kembali ke kode (iii)

function fungsiKesatu() {
  // simulasi delay async sebagai analogi aksi yang lama
  setTimeout(() => {
    console.log('satu');
  }, 1000);
}
function fungsiKedua() {
  console.log('dua');
}
// secara logika yang kita tahu
// seharusnya ini akan berjalan dahulu
fungsiKesatu();
// baru yang ini bukan?
fungsiKedua();

Mari coba kita lihat outputnya !

Kok bisa?

  • Ini bukan berarti bahwa si javascript pilih kasih yah!
  • Pada kode, sebenarnya si fungsiKesatu berjalan duluan, hanya saja, tidak ditungguin sampai selesai, namun langsung ke fungsiKedua dulu
  • fungsiKesatu jalan (duluan) namun tidak ditunggu, kemudian fungsiKedua jalan (cetak 'dua') dan setelah fungsiKesatu selesai, dipanggil kembali dan cetak 'satu'

Bagaimana seandainya...

  • fungsiKesatu adalah proses yang tidak diketahui kapan selesainya
  • fungsiKedua adalah proses yang sequential seperti biasanya
  • Kita menginginkan: setelah fungsiKesatu selesai, baru boleh memanggil fungsiKedua?
  • Ya ! (salah satu) solusinya adalah dengan menggunakan callback !

Mari buat Callback

  • Setelah melihat kasus yang sudah ada, mari kita coba buat callback
  • Callback yang akan dibuat tidak menggunakan permasalahan sebelumnya yah !

Mari buat Callback (ii)

Misalnya kita ingin membuat sebuah fungsi yang menerima array of number yang bisa melakukan pencarian angka ganjil saja

Mari buat Callback (iii)

function pemilahAngka(deretAngka) {
  let hasil = [];

  for (let counter = 0; counter < deretAngka.length; counter++) {
    // modulus / modulo (%) adalah angka sisa pembagian
    if (deretAngka[counter] % 2 === 1) {
      hasil.push(deretAngka[counter]);
    }
  }
  return hasil;
}

const deretAngka = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(pemilahAngka(deretAngka));

Mari buat Callback (iv)

Sekarang kita ingin membuat fungsi pemilahAngka bisa melakukan pemilahan berdasarkan fungsi yang diberikan (callback)

Mari buat Callback (v)

Sekarang mari kita melihat kode dengan callbacknya

Klik di sini

(Kode dituliskan di stackblitz karena sudah melebihi area yang bisa dilihat di slide)

Mari buat Callback (vi)

Mari kita menyelesaikan kasus awal kita tadi !
// karena fungsiKesatu yang harus menunggu fungsiKedua
// maka callbacknya akan dimasukkan ke sini
function fungsiKesatu(fnCallback) {
  setTimeout(() => {
    // ketika timeout sudah selesai console log ini akan berjalan
    console.log('satu');
    // baru setelah itu fnCallback di-invoke
    fnCallback();
  }, 1000);
}
function fungsiKedua() {
  console.log('dua');
}
fungsiKesatu(fungsiKedua);

Nested Callback

Mirip dengan Looping, Callback juga bisa di-nestedkan

Mari kita coba lihat kode nested callbacknya
Klik di sini

(Kode dituliskan di stackblitz karena sudah melebihi area yang bisa dilihat di slide)

Nested Callback (ii)

Penggunaan berlebihan nested callback bisa menghasilkan sesuatu yang "menyenangkan"

hadouken

Umumnya dikenal dengan nama Callback Hell atau Pyramid of Doom

QnA

Waktunya Tantangan

Klik di sini

Referensi

  • https://www.w3schools.com/js/js_callback.asp
  • https://github.com/withered-flowers/education-callback-3
  • https://www.freecodecamp.org/news/discover-the-power-of-first-class-functions-fd0d7b599b69/
  • https://www.javascripttutorial.net/javascript-callback/
withered-flowers (2022)