Μοτίβα AbortController
Τα AbortController και AbortSignal είναι πλήρεις υλοποιήσεις WHATWG στο Phasis. Διατίθενται επίσης τα τυπικά βοηθήματα σύνθεσης (AbortSignal.any, AbortSignal.timeout). Αυτή η σελίδα καλύπτει τα μοτίβα που χρησιμοποιούνται στην πράξη και τον τρόπο διάδοσης της ακύρωσης πέρα από το όριο PHP.
Ακύρωση fetch
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort(); // p rejects with AbortError DOMException
Ο λόγος είναι από προεπιλογή AbortError, αλλά μπορείτε να ορίσετε τον δικό σας:
ctrl.abort(new Error('user cancelled'));
Το fetch απορρίπτεται με ό,τι περάσατε.
Χρονικό όριο
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
Το AbortSignal.timeout(ms) επιστρέφει ένα σήμα που ματαιώνεται μόνο του μετά από ms. Ο χρονοδιακόπτης ενεργοποιείται μέσω του βρόχου συμβάντων της μηχανής, του ίδιου που κινεί τα setTimeout / queueMicrotask (δείτε το API: Βρόχος συμβάντων). Η μεταφορά fetch ελέγχει το σήμα κατά τη διάρκεια της μεταφοράς — για το προεπιλεγμένο CurlTransport, μέσω του CURLOPT_PROGRESSFUNCTION — ώστε το αίτημα να ματαιώνεται αμέσως μόλις εκπνεύσει η προθεσμία.
Ο βρόχος χρησιμοποιεί από προεπιλογή εικονικό χρόνο: προχωρά το ρολόι του έως την επόμενη εκκρεμή προθεσμία αντί να περιμένει PHP, οπότε ένα fetch(url, { signal: AbortSignal.timeout(5000) }) είτε ολοκληρώνεται πριν από την προθεσμία είτε ματαιώνεται στο επόμενο βήμα του βρόχου — δεν κάνει ποτέ το PHP να περιμένει. Για ρυθμό πραγματικού χρόνου, ο κεντρικός κώδικας πρέπει να κινεί το tickEventLoop() με βάση ένα ρολόι πραγματικού χρόνου.
Αγώνας: κερδίζει η πρώτη ακύρωση
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
Διάδοση μεταξύ επιπέδων
Τυλίξτε τη δική σας ασύγχρονη εργασία σε έναν βρόχο που λαμβάνει υπόψη το σήμα:
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 κληρονομεί απευθείας το σήμα· το χειροκίνητο if (signal.aborted) καλύπτει τα κενά μεταξύ αιτημάτων, όταν διαφορετικά ο βρόχος της σελίδας θα συνέχιζε να εκτελείται.
Ακρόαση του συμβάντος ακύρωσης
ctrl.signal.addEventListener('abort', () => {
releaseDatabaseLock();
cancelDownstreamWork();
});
Το signal.reason ορίζεται πριν ενεργοποιηθούν οι ακροατές.
Σήμα σε προσαρμοσμένη μεταφορά fetch
Αν αντικαταστήσετε τη μεταφορά μέσω του setFetchTransport(), το σήμα περνά στην κλήσιμη συνάρτησή σας ως JsObject. Λαμβάνετέ το υπόψη ελέγχοντάς το περιοδικά:
$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',
);
}
// ...
});
Η ρίψη του TransportException με kind: 'aborted' κάνει το JS-side fetch να απορριφθεί με AbortError DOMException — όπως αν είχε εκτελεστεί ο βρόχος ακύρωσης της προδιαγραφής.
Για backend με εγγενή ακύρωση (το Guzzle on_progress, το Symfony ResponseInterface::cancel), συνδέστε την ίδια μορφή ελέγχου και εκτόξευσης.
Μοτίβα που δεν λειτουργούν ακόμη
signal.addEventListener('abort', () => fetch(cleanupUrl))— οι ακροατές ενεργοποιούνται σύγχρονα· το fetch καθαρισμού ξεκινά, αλλά δεν ολοκληρώνεται κατά την αποστολή του συμβάντος ακύρωσης. Προγραμματίστε το μέσω του περιβάλλοντοςawait.
Το setTimeout(() => ctrl.abort(), N) λειτουργεί (η οικογένεια χρονομετρητών είναι διαθέσιμη και καλύπτεται από το WPT), αλλά το AbortSignal.timeout(N) είναι συντομότερο και δηλώνει καλύτερα την πρόθεση όταν θέλετε απλώς ένα σήμα ακύρωσης μετά την προθεσμία.
Δείτε επίσης
- Μεταφορά Fetch — πλήρης διεπαφή αιτήματος/απόκρισης/σήματος για προσαρμοσμένες μεταφορές.
- Web APIs (WPT) — ποσοστό επιτυχίας WPT για AbortController/AbortSignal.