Senin, 27 April 2020

Cara Membuat Callback Function di Javascript

Cara Membuat Callback Function di Javascript

Hal yang membuat bingung ketika kita bekerja dengan synchronous dan asynchronous program adalah bagaimana menangani suatu nilai yang didapatkan secara asynchronous pada program yang berjalan secara synchronous. 


Contohnya seperti kode berikut:

  1. const getCake = () => {

  2.  let cake = null;

  3.  console.log("Sedang membuat kue, silakan tunggu ....")

  4.  setTimeout(() => {

  5.    cake = "Kue Selesai!"

  6.  }, 3000)

  7.  return cake;

  8. }

  9.  

  10. const cake = getCake();

  11. console.log(cake);

  12.  

  13. /*output:

  14. Sedang membuat kue, silakan tunggu ....

  15. null

  16. */


Jika kita melakukan hal seperti ini untuk mencetak nilai cake yang sesungguhnya, maka hal tersebut tidak akan pernah terjadi. Karena seperti yang sudah kita ketahui fungsi setTimeout() tidak akan menghentikan JavaScript untuk mengeksekusi kode yang ada selanjutnya. Jadi fungsi getCake() akan selalu mengembalikan nilai null, karena kode return cake akan dieksekusi terlebih dahulu dibandingkan dengan cake = “Kue Selesai!”. Kode asynchronous perlu disusun dengan cara yang berbeda dari synchronous code. Cara paling dasar adalah dengan menggunakan callback function.
Apa itu callback function? Mari kita bayangkan kembali melalui pandangan dunia nyata. Kita menunggu pesanan kopi datang di meja kita tapi , pada saat itu juga kita tidak bisa berada terus di tempat itu karena ada urusan mendadak. Pada kasus ini mungkin terdapat dua aksi yang bisa kita lakukan:
  • (Synchronous) Kita tetap menunggu di meja hingga kopi itu datang dan kemudian meninggalkan kedai kopi.
  • (Asynchronous) Kita meminta tolong kepada teman kita untuk menerima kopi itu, dan bertemu nanti untuk memberikan kopinya. Sehingga kita tidak perlu menunggu untuk meninggalkan kedai kopi.
Nah pada JavaScript, teman kita berperan layaknya callback function. Ia diperintahkan pada sebuah fungsi asynchronous kemudian akan dipanggil/digunakan ketika tugas itu selesai.
Bagaimana cara melakukannya? Yang pertama kita tambahkan parameter dengan nama callback pada fungsi asynchronous.

  1. const getCake = callback => {

  2.  let cake = null;

  3.  console.log("Sedang membuat kue, silakan tunggu ....")

  4.  setTimeout(() => {

  5.    cake = "Kue Selesai!";

  6.  }, 3000)

  7.  return cake;

  8. }


Kemudian kita panggil/gunakan callback yang diisikan dengan data yang akan dibawa (cake) ketika task selesai dilakukan.

  1. setTimeout(function() {

  2.    cake = "Kue Selesai!";

  3.    callback(cake);

  4. }, 3000)


Setelah menggunakan callback, fungsi tidak perlu lagi mengembalikan nilai. Sehingga kita bisa hapus kode return cake;. Sehingga keseluruhan fungsi akan tampak seperti ini:

  1. const getCake = callback => {

  2.  let cake = null;

  3.  console.log("Sedang membuat kue, silakan tunggu ....")

  4.  setTimeout(() => {

  5.    cake = "Kue Selesai!";

  6.    callback(cake);

  7.  }, 3000)

  8. }


Kemudian untuk menggunakan fungsi getCake, kita ubah kode dari:

  1. const cake = getCake();

  2. console.log(cake);


Menjadi:

  1. getCake(cake => {

  2.  console.log(cake);

  3. })


Sehingga ketika dijalankan akan sesuai dengan harapan kita.

  1. const getCake = callback => {

  2.  let cake = null;

  3.  console.log("Sedang membuat kue, silakan tunggu ....")

  4.  setTimeout(() => {

  5.    cake = "Kue Selesai!";

  6.    callback(cake);

  7.  }, 3000)

  8. }

  9.  

  10. getCake(cake => {

  11.  console.log(cake);

  12. })

  13.  

  14. /* output:

  15. Sedang membuat kue, silakan tunggu ....

  16. ---- setelah 3 detik ----

  17. Kue Selesai!

  18. */



Callback Hell

Kita sudah mengetahui bahwa callback dibutuhkan untuk mendapatkan nilai yang berasal dari asynchronous function. Lantas bagaimana jika terdapat proses satu sama lain yang saling bergantungan? Contohnya, untuk membuat kue tahapan yang perlu kita lakukan adalah:
  1. Mempersiapkan bahan
  2. Membuat adonan
  3. Menyiapkan adonan ke cetakan
  4. Memanggang adonan
Tahapan tersebut sangat tergantung satu sama lain. Kita tidak bisa memanggang adonan sebelum membuat adonannya, dan kita tidak bisa membuat adonan tanpa mempersiapkan bahannya terlebih dahulu. Jika seluruh tahapan tersebut berjalan secara synchronous, mungkin kita bisa melakukanya seperti ini:

  1. function makeACake(...rawIngredients) {

  2.  const ingredients = gatheringIngredients(rawIngredients),

  3.  dough = makeTheDough(ingredients),

  4.  pouredDough = pourDough(dough),

  5.  cake = bakeACake(pourDough),

  6.  console.log(cake);

  7. }


Namun jika fungsi-fungsi tersebut berjalan secara asynchronous, maka kita akan membuat yang namanya callback hell. Callback hell terjadi karena banyak sekali callback function yang bersarang karena saling membutuhkan satu sama lain, sehingga kode akan tampak seperti ini:

  1. function makeACake(...rawIngredients) {

  2.  gatheringIngredients(rawIngredients, function(ingridients) {

  3.    makeTheDough(ingridients, function(dough) {

  4.      pourDough(dough, function(pouredDough) {

  5.        bakeACake(pouredDough, function(cake) {

  6.          console.log(cake);

  7.        });

  8.      });

  9.    });

  10.  });

  11. }


Melihat kode seperti ini saja, kepala jadi pusing. Terbayang sulitnya memelihara kode ini di masa yang akan datang.
Lantas apa solusi agar kita dapat menghindari callback hell? Salah satunya adalah dengan menggunakan Promise.

  1. function makeACake(...rawIngredients) {

  2.  gatheringIngredients(rawIngredients)

  3.  .then(makeTheDough)

  4.  .then(pourDough)

  5.  .then(bakeACake)

  6.  .then(console.log);

  7. }


Dengan Promise, kita dapat meminimalisir callback hell dan mengubahnya menjadi kode yang sangat mudah dibaca. Bahkan dengan kode seperti itu, non-developer pun dapat mengerti apa maksud dari kode tersebut
Cara Membuat Fungsi setTimeout didalam Javascript

Cara Membuat Fungsi setTimeout didalam Javascript

Fungsi setTimeout() merupakan cara yang paling mudah untuk membuat kode kita dijalankan secara asynchronous.

Fungsi ini menerima dua buah parameter. 
Pertama adalah fungsi yang akan dijalankan secara asynchronous, dan kedua adalah nilai number dalam milisecond sebagai nilai tunggu sebelum fungsi dijalankan. Contoh penggunaannya adalah seperti ini:

  1. console.log("Selamat datang!");

  2. setTimeout(() => {

  3.  console.log("Terimakasih sudah mampir, silakan datang kembali!")

  4. }, 3000)

  5. console.log("Ada yang bisa dibantu?")


Jika kita hanya mengenal program secara synchronous, maka kita dapat membayangkan hasilnya memiliki urutan sebagai berikut:
  • Mencetak -> Selamat datang!
  • Menunggu selama tiga detik
  • Mencetak -> Terima kasih sudah mampir, silakan datang kembali!
  • Mencetak -> Ada yang bisa dibantu?
Namun nyatanya setTimeout() tidak akan menghentikan JavaScript untuk melakukan eksekusi kode pada baris berikutnya. Sehingga urutannya menjadi seperti berikut:
  • Mencetak -> Selamat datang!
  • Mencetak -> Ada yang bisa dibantu?
  • Menunggu selama tiga detik
  • Mencetak -> Terimakasih sudah mampir, silakan datang kembali!
Jika kode tersebut dijalankan, maka akan menampilkan output sebagai berikut:
20200312170729f414a0fada93abd3a5d0736d14ecf72b.gif
Static Method didalam Class Javascript

Static Method didalam Class Javascript

Seluruh kendaraan pasti butuh yang namanya perawatan bukan? Jika iya, tentu kita perlu membuat method repair untuk memperbaiki kendaraan tersebut. 
Dalam analogi dunia nyata, ketika kendaraan mengalami kerusakan maka kendaraan tersebut akan diperbaiki di bengkel (factory), sehingga kita perlu membuat class baru yang berperan sebagai factory, sebutlah class tersebut VehicleFactory. Di dalam kelas VehicleFactory terdapat satu method repair() yang dapat menerima banyak kendaraan sebagai parameternya.

  1. class Vehicle {

  2.   constructor(licensePlate, manufacture) {

  3.       this.licensePlate = licensePlate;

  4.       this.manufacture = manufacture;

  5.       this.engineActive = false;

  6.   }

  7.    /*

  8.   kode lainnya

  9.   */

  10. }

  11.  

  12. /* kode lainnya dalam pembuatan class Car, 

  13. Motorcycle, dsb. */

  14.  

  15.  

  16. class VehicleFactory {

  17.  repair(vehicles) {

  18.     vehicles.forEach(vehicle => {

  19.       console.log(`Kendaraan ${vehicle.licensePlate} sedang melakukan perawatan`)

  20.     })

  21.   }

  22. }


Untuk mengakses method dari class, sejauh ini kita perlu membuat instance dari classnya terlebih dahulu. Sehingga untuk memanggil repair(), kita perlu membuat instance dari class VehicleFactory

  1. const johnCar = new Car("H121S", "Honda", 4);

  2. const tomMotor = new Motorcycle("GF121J", "Yamaha", 2);

  3. const dimasCar = new Car("TA1408K", "Tesla", 4);

  4.  

  5. /* Membuat instance untuk memanggil fungsi repair */

  6. const vehicleFactory = new VehicleFactory();

  7. vehicleFactory.repair([johnCar, tomMotor, dimasCar]);

  8.  

  9. /* output:

  10. Kendaraan H121S sedang melakukan perawatan

  11. Kendaraan GF121J sedang melakukan perawatan

  12. Kendaraan TA1408K sedang melakukan perawatan

  13. */


Kode tersebut berjalan sesuai harapan namun tidak efektif. Mengapa? Karena kita perlu membuat instance untuk sekedar memanggil satu fungsi dari class-nya tersebut. Membuat instance adalah membuat sebuah objek baru yang terbentuk melalui blueprint sehingga membutuhkan memori ekstra. Jika kita dapat mengakses method tersebut tanpa melalui instance mengapa tidak? Pada kasus inilah kita membutuhkan sebuah static method. Static method merupakan method yang tidak dapat dipanggil oleh instance dari class, namun dapat dipanggil melalui class-nya sendiri.
Pada ES6 class kita dapat membuat static method dengan menambahkan keyword static sebelum deklarasi method-nya:

  1. class Vehicle {

  2.   constructor(licensePlate, manufacture) {

  3.       this.licensePlate = licensePlate;

  4.       this.manufacture = manufacture;

  5.       this.engineActive = false;

  6.   }

  7.    /*

  8.   kode lainnya

  9.   */

  10. }

  11.  

  12. /* kode lainnya dalam pembuatan class Car, 

  13. Motorcycle, dsb. */

  14.  

  15. class VehicleFactory {

  16.  static repair(vehicles) {

  17.     vehicles.forEach(vehicle => {

  18.       console.log(`Kendaraan ${vehicle.licensePlate} sedang melakukan perawatan`)

  19.     })

  20.   }

  21. }


Kemudian untuk memanggil methodnya kita bisa panggil melalui class Vehicle kemudian repair().
Seluruh kendaraan pasti butuh yang namanya perawatan bukan? Jika iya, tentu kita perlu membuat method repair untuk memperbaiki kendaraan tersebut. Dalam analogi dunia nyata, ketika kendaraan mengalami kerusakan maka kendaraan tersebut akan diperbaiki di bengkel (factory), sehingga kita perlu membuat class baru yang berperan sebagai factory, sebutlah class tersebut VehicleFactory. Di dalam kelas VehicleFactory terdapat satu method repair() yang dapat menerima banyak kendaraan sebagai parameternya. 

  1. class Vehicle {

  2.   constructor(licensePlate, manufacture) {

  3.       this.licensePlate = licensePlate;

  4.       this.manufacture = manufacture;

  5.       this.engineActive = false;

  6.   }

  7.    /*

  8.   kode lainnya

  9.   */

  10. }

  11.  

  12. /* kode lainnya dalam pembuatan class Car, 

  13. Motorcycle, dsb. */

  14.  

  15.  

  16. class VehicleFactory {

  17.  repair(vehicles) {

  18.     vehicles.forEach(vehicle => {

  19.       console.log(`Kendaraan ${vehicle.licensePlate} sedang melakukan perawatan`)

  20.     })

  21.   }

  22. }


Untuk mengakses method dari class, sejauh ini kita perlu membuat instance dari classnya terlebih dahulu. Sehingga untuk memanggil repair(), kita perlu membuat instance dari class VehicleFactory

  1. const johnCar = new Car("H121S", "Honda", 4);

  2. const tomMotor = new Motorcycle("GF121J", "Yamaha", 2);

  3. const dimasCar = new Car("TA1408K", "Tesla", 4);

  4.  

  5. /* Membuat instance untuk memanggil fungsi repair */

  6. const vehicleFactory = new VehicleFactory();

  7. vehicleFactory.repair([johnCar, tomMotor, dimasCar]);

  8.  

  9. /* output:

  10. Kendaraan H121S sedang melakukan perawatan

  11. Kendaraan GF121J sedang melakukan perawatan

  12. Kendaraan TA1408K sedang melakukan perawatan

  13. */


Kode tersebut berjalan sesuai harapan namun tidak efektif. Mengapa? Karena kita perlu membuat instance untuk sekedar memanggil satu fungsi dari class-nya tersebut. Membuat instance adalah membuat sebuah objek baru yang terbentuk melalui blueprint sehingga membutuhkan memori ekstra. Jika kita dapat mengakses method tersebut tanpa melalui instance mengapa tidak? Pada kasus inilah kita membutuhkan sebuah static method. Static method merupakan method yang tidak dapat dipanggil oleh instance dari class, namun dapat dipanggil melalui class-nya sendiri.
Pada ES6 class kita dapat membuat static method dengan menambahkan keyword static sebelum deklarasi method-nya:

  1. class Vehicle {

  2.   constructor(licensePlate, manufacture) {

  3.       this.licensePlate = licensePlate;

  4.       this.manufacture = manufacture;

  5.       this.engineActive = false;

  6.   }

  7.    /*

  8.   kode lainnya

  9.   */

  10. }

  11.  

  12. /* kode lainnya dalam pembuatan class Car, 

  13. Motorcycle, dsb. */

  14.  

  15. class VehicleFactory {

  16.  static repair(vehicles) {

  17.     vehicles.forEach(vehicle => {

  18.       console.log(`Kendaraan ${vehicle.licensePlate} sedang melakukan perawatan`)

  19.     })

  20.   }

  21. }


Kemudian untuk memanggil methodnya kita bisa panggil melalui class Vehicle kemudian repair().