Javascript 如何取消 HTTP fetch() 请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31061838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I cancel an HTTP fetch() request?
提问by Sam Lee
There is a new API for making requests from JavaScript: fetch(). Is there any built in mechanism for canceling these requests in-flight?
有一个用于从 JavaScript 发出请求的新 API:fetch()。是否有任何内置机制可以取消这些正在进行的请求?
回答by SudoPlz
TL/DR:
TL/DR:
fetch
now supports a signal
parameter as of 20 September 2017, but not
all browsers seem support this at the moment.
fetch
现在支持signal
截至 2017 年 9 月 20 日的参数,但目前似乎并非所有浏览器都支持此参数。
2020 UPDATE:Most major browsers (Edge, Firefox, Chrome, Safari, Opera, and a few others) support the feature, which has become part of the DOM living standard. (as of 5 March 2020)
2020 更新:大多数主要浏览器(Edge、Firefox、Chrome、Safari、Opera 和其他一些浏览器)都支持该功能,该功能已成为DOM 生活标准的一部分。(截至 2020 年 3 月 5 日)
This is a change we will be seeing very soon though, and so you should be able to cancel a request by using an AbortController
s AbortSignal
.
这是我们很快就会看到的更改,因此您应该能够使用AbortController
s取消请求AbortSignal
。
Long Version
长版
How to:
如何:
The way it works is this:
它的工作方式是这样的:
Step 1: You create an AbortController
(For now I just used this)
第 1 步:您创建一个AbortController
(现在我只使用了这个)
const controller = new AbortController()
const controller = new AbortController()
Step 2: You get the AbortController
s signal like this:
第 2 步:您会得到这样的AbortController
s 信号:
const signal = controller.signal
const signal = controller.signal
Step 3: You pass the signal
to fetch like so:
第 3 步:您通过signal
fetch 像这样:
fetch(urlToFetch, {
method: 'get',
signal: signal, // <------ This is our AbortSignal
})
Step 4: Just abort whenever you need to:
第 4 步:只需在需要时中止:
controller.abort();
controller.abort();
Here's an example of how it would work (works on Firefox 57+):
这是它如何工作的示例(适用于 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>
Sources:
资料来源:
- The final version of AbortControllerhas been added to the DOM specification
- The corresponding PRfor the fetch specification is now merged.
- Browser bugs tracking the implementation of AbortController is available here: Firefox: #1378342, Chromium: #750599, WebKit: #174980, Edge: #13009916.
回答by Jayen
https://developers.google.com/web/updates/2017/09/abortable-fetch
https://developers.google.com/web/updates/2017/09/abortable-fetch
https://dom.spec.whatwg.org/#aborting-ongoing-activities
https://dom.spec.whatwg.org/#aborting-ongoing-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();
works in edge 16 (2017-10-17), firefox 57 (2017-11-14), desktop safari 11.1 (2018-03-29), ios safari 11.4 (2018-03-29), chrome 67 (2018-05-29), and later.
适用于 edge 16 (2017-10-17), firefox 57 (2017-11-14), desktop safari 11.1 (2018-03-29), ios safari 11.4 (2018-03-29), chrome 67 (2018-05) -29),以及以后。
on older browsers, you can use github's whatwg-fetch polyfilland AbortController polyfill. you can detect older browsers and use the polyfills conditionally, too:
在较旧的浏览器上,您可以使用github 的 whatwg-fetch polyfill和AbortController polyfill。您也可以检测较旧的浏览器并有条件地使用 polyfill:
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
回答by AnthumChris
As of Feb 2018, fetch()
can be cancelled with the code below on Chrome (read Using Readable Streamsto enable Firefox support). No error is thrown for catch()
to pick up, and this is a temporary solution until AbortController
is fully adopted.
截至 2018 年 2 月,fetch()
可以在 Chrome 上使用以下代码取消(阅读使用可读流以启用 Firefox 支持)。没有错误被抛出catch()
,这是一个临时解决方案,直到AbortController
被完全采用。
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();
})
}
}
}
}
回答by Brad
As for now there is no proper solution, as @spro says.
至于现在没有合适的解决方案,正如@spro 所说。
However, if you have an in-flight response and are using ReadableStream, you can close the stream to cancel the request.
但是,如果您有一个进行中的响应并且正在使用 ReadableStream,您可以关闭流以取消请求。
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();
});
回答by 0xC0DEGURU
Let's 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;
}
Please have in mind that the code is not tested! Let me know if you have tested it and something didn't work. It may give you warnings that you try to overwrite the 'fetch' function from the JavaScript official library.
请记住,代码未经测试!让我知道您是否已经对其进行了测试并且某些功能不起作用。它可能会警告您尝试覆盖 JavaScript 官方库中的 'fetch' 函数。