Câu trả lời:
fetch
hiện hỗ trợ một signal
tham số kể từ ngày 20 tháng 9 năm 2017, nhưng hiện tại không phải tất cả các trình duyệt đều hỗ trợ điều này .
CẬP NHẬT 2020: Hầu hết các trình duyệt chính (Edge, Firefox, Chrome, Safari, Opera và một vài trình duyệt khác) đều hỗ trợ tính năng này , đã trở thành một phần của tiêu chuẩn sống DOM . (kể từ ngày 5 tháng 3 năm 2020)
Đây là một thay đổi mà chúng tôi sẽ sớm thấy, và vì vậy bạn sẽ có thể hủy yêu cầu bằng cách sử dụng AbortController
s AbortSignal
.
Cách thức hoạt động là thế này:
Bước 1 : Bạn tạo một AbortController
(Bây giờ tôi chỉ sử dụng cái này )
const controller = new AbortController()
Bước 2 : Bạn nhận được AbortController
tín hiệu s như thế này:
const signal = controller.signal
Bước 3 : Bạn vượt qua signal
để tìm nạp như vậy:
fetch(urlToFetch, {
method: 'get',
signal: signal, // <------ This is our AbortSignal
})
Bước 4 : Chỉ cần hủy bỏ bất cứ khi nào bạn cần:
controller.abort();
Đây là một ví dụ về cách nó sẽ hoạt động (hoạt động trên Firefox 57+):
<script>
// Create an instance.
const controller = new AbortController()
const signal = controller.signal
/*
// Register a listenr.
signal.addEventListener("abort", () => {
console.log("aborted!")
})
*/
function beginFetching() {
console.log('Now fetching');
var urlToFetch = "https://httpbin.org/delay/3";
fetch(urlToFetch, {
method: 'get',
signal: signal,
})
.then(function(response) {
console.log(`Fetch complete. (Not aborted)`);
}).catch(function(err) {
console.error(` Err: ${err}`);
});
}
function abortFetching() {
console.log('Now aborting');
// Abort.
controller.abort()
}
</script>
<h1>Example of fetch abort</h1>
<hr>
<button onclick="beginFetching();">
Begin
</button>
<button onclick="abortFetching();">
Abort
</button>
AbortController is not defined
. Dù sao đây chỉ là một bằng chứng về khái niệm, ít nhất những người có Firefox 57+ có thể thấy nó hoạt động
https://developers.google.com/web/updates/2017/09/abortable-fetch
https://dom.spec.whatwg.org/#aborting-ongaging-activities
// setup AbortController
const controller = new AbortController();
// signal to pass to fetch
const signal = controller.signal;
// fetch as usual
fetch(url, { signal }).then(response => {
...
}).catch(e => {
// catch the abort if you like
if (e.name === 'AbortError') {
...
}
});
// when you want to abort
controller.abort();
hoạt động ở cạnh 16 (2017-10-17), firefox 57 (2017-11-14), máy tính để bàn 11.1 (2018-03-29), ios safari 11.4 (2018-03-29), chrome 67 (2018-05 -29) và sau đó.
trên các trình duyệt cũ hơn, bạn có thể sử dụng polyfill whatwg-fetch polyfill và AbortControll của github . bạn cũng có thể phát hiện các trình duyệt cũ hơn và sử dụng các polyfill theo điều kiện :
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
import {fetch} from 'whatwg-fetch'
// use native browser implementation if it supports aborting
const abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch
Kể từ tháng 2 năm 2018, fetch()
có thể bị hủy bằng mã bên dưới trên Chrome (đọc Sử dụng luồng có thể đọc để bật hỗ trợ Firefox). Không có lỗi được đưa ra catch()
để nhận, và đây là một giải pháp tạm thời cho đến khi AbortController
được chấp nhận hoàn toàn.
fetch('YOUR_CUSTOM_URL')
.then(response => {
if (!response.body) {
console.warn("ReadableStream is not yet supported in this browser. See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream")
return response;
}
// get reference to ReadableStream so we can cancel/abort this fetch request.
const responseReader = response.body.getReader();
startAbortSimulation(responseReader);
// Return a new Response object that implements a custom reader.
return new Response(new ReadableStream(new ReadableStreamConfig(responseReader)));
})
.then(response => response.blob())
.then(data => console.log('Download ended. Bytes downloaded:', data.size))
.catch(error => console.error('Error during fetch()', error))
// Here's an example of how to abort request once fetch() starts
function startAbortSimulation(responseReader) {
// abort fetch() after 50ms
setTimeout(function() {
console.log('aborting fetch()...');
responseReader.cancel()
.then(function() {
console.log('fetch() aborted');
})
},50)
}
// ReadableStream constructor requires custom implementation of start() method
function ReadableStreamConfig(reader) {
return {
start(controller) {
read();
function read() {
reader.read().then(({done,value}) => {
if (done) {
controller.close();
return;
}
controller.enqueue(value);
read();
})
}
}
}
}
Hiện tại không có giải pháp thích hợp, như @spro nói.
Tuy nhiên, nếu bạn có phản hồi trên máy bay và đang sử dụng ReadableStream, bạn có thể đóng luồng để hủy yêu cầu.
fetch('http://example.com').then((res) => {
const reader = res.body.getReader();
/*
* Your code for reading streams goes here
*/
// To abort/cancel HTTP request...
reader.cancel();
});
Hãy để polyfill:
if(!AbortController){
class AbortController {
constructor() {
this.aborted = false;
this.signal = this.signal.bind(this);
}
signal(abortFn, scope) {
if (this.aborted) {
abortFn.apply(scope, { name: 'AbortError' });
this.aborted = false;
} else {
this.abortFn = abortFn.bind(scope);
}
}
abort() {
if (this.abortFn) {
this.abortFn({ reason: 'canceled' });
this.aborted = false;
} else {
this.aborted = true;
}
}
}
const originalFetch = window.fetch;
const customFetch = (url, options) => {
const { signal } = options || {};
return new Promise((resolve, reject) => {
if (signal) {
signal(reject, this);
}
originalFetch(url, options)
.then(resolve)
.catch(reject);
});
};
window.fetch = customFetch;
}
Xin lưu ý rằng mã không được kiểm tra! Hãy cho tôi biết nếu bạn đã thử nghiệm nó và một cái gì đó không hoạt động. Nó có thể đưa ra cảnh báo rằng bạn cố gắng ghi đè chức năng 'tìm nạp' từ thư viện chính thức JavaScript.