Lewati ke konten

Pola AbortController

AbortController dan AbortSignal adalah implementasi WHATWG lengkap di Phasis. Helper komposisi standar (AbortSignal.any, AbortSignal.timeout) juga tersedia. Halaman ini membahas pola yang umum digunakan dan cara pembatalan merambat melintasi batas PHP.

Membatalkan fetch

JavaScript
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort();                     // p rejects with AbortError DOMException

Alasannya secara bawaan adalah AbortError, tetapi Anda dapat memberikan alasan sendiri:

JavaScript
ctrl.abort(new Error('user cancelled'));

fetch menolak dengan nilai apa pun yang Anda berikan.

Batas waktu

JavaScript
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });

AbortSignal.timeout(ms) mengembalikan sinyal yang membatalkan dirinya sendiri setelah ms. Timer berjalan melalui event loop mesin yang sama dengan yang menjalankan setTimeout / queueMicrotask (lihat API: Event loop). Transportasi fetch memeriksa sinyal selama transfer — untuk CurlTransport bawaan, melalui CURLOPT_PROGRESSFUNCTION — sehingga permintaan segera dibatalkan saat tenggat tercapai.

Secara bawaan, loop menggunakan waktu virtual: jamnya maju ke tenggat tertunda berikutnya alih-alih menunggu PHP, sehingga fetch(url, { signal: AbortSignal.timeout(5000) }) selesai sebelum tenggat atau dibatalkan pada tick loop berikutnya — tidak pernah membuat PHP menunggu. Pengaturan waktu nyata mengharuskan host menjalankan tickEventLoop() berdasarkan jam dinding.

Race: pembatalan pertama menang

JavaScript
const user = new AbortController();
const signal = AbortSignal.any([user.signal, AbortSignal.timeout(10_000)]);
const res = await fetch(url, { signal });
// res rejects if EITHER the user clicks cancel OR 10s elapses

Propagasi melalui lapisan

Bungkus pekerjaan async Anda sendiri dengan loop yang memperhatikan sinyal:

JavaScript
async function fetchPaged(url, signal) {
  const out = [];
  for (let page = 1; ; page++) {
    if (signal.aborted) throw signal.reason;
    const r = await fetch(`${url}?page=${page}`, { signal });
    const data = await r.json();
    if (data.length === 0) break;
    out.push(...data);
  }
  return out;
}

Fetch mewarisi sinyal secara langsung; if (signal.aborted) manual menangani jeda antarpermintaan saat loop halaman mungkin terus berjalan.

Mendengarkan event pembatalan

JavaScript
ctrl.signal.addEventListener('abort', () => {
  releaseDatabaseLock();
  cancelDownstreamWork();
});

signal.reason ditetapkan sebelum listener dijalankan.

Sinyal dalam transportasi fetch khusus

Jika Anda mengganti transportasi melalui setFetchTransport(), sinyal diteruskan ke callable Anda sebagai JsObject. Patuhi sinyal dengan memeriksanya secara berkala:

PHP
$engine->setFetchTransport(function (array $req, $signal) {
    $ch = curl_init($req['url']);
    // ...
    if ($signal !== null) {
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION,
            fn () => $signal->get('aborted')->value ? 1 : 0);
        curl_setopt($ch, CURLOPT_NOPROGRESS, false);
    }
    $body = curl_exec($ch);
    if (curl_errno($ch) === CURLE_ABORTED_BY_CALLBACK) {
        throw new \Phasis\BuiltIn\Fetch\TransportException(
            'aborted', 'aborted',
        );
    }
    // ...
});

Melempar TransportException dengan kind: 'aborted' membuat JS-side fetch menolak dengan AbortError DOMException — sama seperti jika abort-loop spesifikasi dijalankan.

Untuk backend dengan pembatalan bawaan (Guzzle milik on_progress, Symfony milik ResponseInterface::cancel), gunakan pola pemeriksaan dan pelemparan yang sama.

Pola yang belum berfungsi

  • signal.addEventListener('abort', () => fetch(cleanupUrl)) — listener dijalankan secara sinkron; fetch pembersihan dimulai tetapi tidak akan selesai saat event pembatalan diproses. Jadwalkan melalui await di sekitarnya.

setTimeout(() => ctrl.abort(), N) berfungsi (keluarga timer tersedia dan tercakup WPT), tetapi AbortSignal.timeout(N) lebih ringkas dan lebih jelas menyampaikan maksud ketika Anda hanya memerlukan sinyal untuk membatalkan setelah tenggat.

Lihat juga

  • Transportasi fetch — antarmuka lengkap permintaan/respons/sinyal untuk transportasi khusus.
  • API Web (WPT) — tingkat kelulusan WPT AbortController/AbortSignal.