写在前面
在网页中,Ajax和Fetch是最常用的发起网络请求的两种方式。在面试中,关于这两者的区别也会被提及。你也许听说过这么一个说法,Ajax是可以取消的,Fetch是不可以取消的。真的是这样吗?
取消Ajax
使用ajax发起一个网络请求的代码大致如下:
var xhr = new XMLHttpRequest();xhr.open("GET", url);xhr.onreadystatechange = function(){};xhr.send();
想要中断这个ajax请求,可以直接调用
xhr.abort()
取消fetch
使用fetch发起一个网络请求的代码大致如下:
fetch(url) .then(r => r.json()) .then(response => { }) .catch(err => { console.error("Error in fetching!", err); });
fetch是基于promise的,可以在页面主线程、worker等地方使用,十分的方便。
想取消一个fetch请求,可以使用AbortController
.
AbortController代表一个控制器对象,允许你在需要时中止一个或多个DOM请求。直接来看示例代码:
var controller = new AbortController();var signal = controller.signal; // 将signal传入fetch的第二个参数fetch(url, { signal }) .then(function(response) { ... }).catch(function(err) { if (err.name === 'AbortError') { console.log('Fetch was aborted'); } else { console.error('Oops!', err); } }); setTimeout(() => { controller.abort(); // 取消fetch请求}, 1000);
当我们主动取消fetch时,fetch的promise 会 reject 以下错误:
new DOMException('Aborted', 'AbortError')
这个时候,会进入fecth的catch逻辑块。
当然,如果fetch已经resolve了,我们就无法取消fetch了。
AbortController 当前的兼容性如下:
polyfills如下:
https://www.npmjs.com/package/abort-controller
https://www.npmjs.com/package/abortcontroller-polyfill
写在后面
取消网络请求是一个很重要的点,特别是在页面中有大量请求,而用户切到其他页面时,适当的取消pending中的网络请求,可以减少网络资源的浪费和页面卡顿,提升用户体验。fetch,也是可以取消的。
最后,推荐一个不错的fetch库: