1 September 2021

Fetch: Membatalkan

Seperti yang kita tahu, fetch mengembalikan promise dan Javascript secara umum tidak memiliki konsep untuk ???membatalkan??? sebuah janji (Promise). Jadi, bagaimana kita bisa membatalkan fetch yang sedang dijalankan? misalnya, jika tindakan pengguna pada situs kita mengindikasikan bahwa fetch sudah tidak dibutuhkan lagi.

Terdapat objek bawaan khusus untuk tujuan ini: AbortContoller. Metode tersebut dapat digunakan untuk membatalkan tidak hanya fetch, tetapi tugas asingkron lainnya.

Penggunaannya sangat mudah:

Objek AbortController

Membuat sebuah pengontrol (controller)

let controller = new AbortController();

Pengontrol adalah objek yang sangat sederhana.

  • Hanya memiliki satu metode abort(),
  • dan sebuah properti signal yang memungkinkan untuk menyetel listener pada objek pengontrol.

Ketika abort() dipanggil:

  • contoller.signal mengeluarkan event "abort"
  • Properti controller.signal.aborted menjadi bernilai true

Secara Umum, kita memiliki dua pihak dalam prosesnya:

  1. Satu pihak yang melaksanakan tindakan terntentu ketika operasi dibatalkan, itu menyetel listener pada controller.signal.
  2. Satu pihak lainnya yang membatalkan: itu memanggil controller.abort() ketika diperlukan.

Berikut contoh lengkapnya (tanpa fetch)

let controller = new AbortController();
let signal = controller.signal;

// Pihak yang melakukan tindakan tertentu ketika operasi dibatalkan
// mendapatkan objek "signal"
// dan menyetel 'listener' untuk memicu ketika controller.abort() dipanggil
signal.addEventListener('abort', () => alert('abort!'));

// Pihak lain yang membatalkan (penjelasnnya nanti)
controller.abort(); // gagalkan!

// Pemicu 'event' dan nilai 'signal.aborted' menjadi 'true'
alert(signal.aborted); // true

Seperti yang kita lihat, AbortController hanyalah sarana untuk meneruskan event abort() ketika dipanggil.

Kita dapat mengimplementasikan jenis event listener yang sama pada kode kita, walaupun tanpa objek AbortController sama sekali.

Tetapi yang berharga adalah fetch tahu bagaimana bekerja dengan objek AborController, itu terintegrasi dengannya.

Menggunakan dengan fetch

Untuk bisa membatalkan fetch, teruskan properti signal dari AbortController sebagai opsi fetch:

let controller = new AbortController();
fetch(url, {
  signal: controller.signal,
});

Metode fetch mengetahui bagaimana cara bekerja dengan AbortController. Itu akan mendengarkan (listen) event abort pada properti signal.

Sekarang, untuk membatalkannya, panggil controller.abort():

controller.abort();

Kita sudah selesai: fetch mendapatkan event dari properti signal dan membatalkan request.

Ketika fetch dibatalkan, maka promise akan ditolak dengan galat AboutError, jadi kita dapat menanganinya. Misalnya dengan try ... catch.

Berikut adalah contoh penuh untuk menggagalkan fetch setelah 1 detik:

// gagalkan setelah satu detik
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

try {
  let response = await fetch('/article/fetch-abort/demo/hang', {
    signal: controller.signal,
  });
} catch (err) {
  if (err.name == 'AbortError') {
    // menangani ketika digagalkan
    alert('Aborted!');
  } else {
    throw err;
  }
}

AbortController dapat ditingkatkan (scalable)

AbortContoller bersifat scalable, itu memungkinkan untuk membatalkan beberapa fetch sekaligus.

Berikut adalah sketsa dari kode yang terdapat proses fetch ke banyak urls secara paralel, dan menggunakan pengontrol tunggal untuk membatalkan semua proses tersebut:

let urls = [...]; // daftar dari url yang akan diambil secara paralel

let controller = new AbortController();

// larik dari 'fetch promise'
let fetchJobs = urls.map(url => fetch(url, {
  signal: controller.signal
}));

let results = await Promise.all(fetchJobs);

// jika controller.fetch() dipanggil dari tempat tertentu
// itu akan menggagalkan semua 'fetch'

Jika kita memiliki tugas asingkron kita sendiri yang berbeda dari fetch, kita dapat menggunakan AbortController tunggal untuk menghentikannya, bersama dengan metode fetch.

Kita hanya perlu untuk listen pada event abort di tugas kita;

let urls = [...];
let controller = new AbortController();

let ourJob = new Promise((resolve, reject) => { // tugas kita
  ...
  controller.signal.addEventListener('abort', reject);
});

let fetchJobs = urls.map(url => fetch(url, { // pemanggilan metode fetch
  signal: controller.signal
}));

// Menunggu semua metode fetch dan tugas kita secara paralel
let results = await Promise.all([...fetchJobs, ourJob]);

// Jika controller.abort() dipanggil dari suatu tempat,
// itu menggagalkan semua metode fetch dan tugas kita

Kesimpulan

  • AbortController adalah sebuah objek sederhana yang menghasilkan event abort pada properti signal ketika metode abort() dipanggil (dan juga menyetel signal.aborted menjadi true).
  • fetch terintegrasi dengannya: kita meneruskan properti signal sebagai opsi, dan kemudian fetch mendengarkan event yang dihasilkan AbortController. Jadi itu menjadi mungkin ketika ingin menggagalkan proses fetch.
  • Kita dapat menggunakan AbortConntroller pada kode kita. Interaksi "pemanggilan abort()" ??? "Mendengarkan (listen) event abort" sederhana dan universal. Kita dapat menggunakannya walaupun tanpa fetch.
Peta tutorial