前端面试一般喜欢问:
在看来《使用 AbortController 终止 fetch 请求》,觉得写的非常详细,于是提炼下笔记:
在现在的浏览器中,有两种主要的方法发送请求:XMLHttpRequest 和 fetch。XMLHttpRequest 这个接口在浏览器中存在很长一段时间了,fetch 则是 ES2015 引入的特性。
XMLHttpRequest 可以在请求中途终止(abortable)。举个例子
let?xhr?=?new?XMLHttpRequest();
xhr.method?=?'GET';
xhr.url?=?'https://slowmo.glitch.me/5000';
xhr.open(method,?url,?true);
xhr.send();
//?Abort?the?request?at?a?later?stage
abortButton.addEventListener('click',?function()?{
??xhr.abort();
});
fetch 刚开始引入时并不支持终止请求。Github 上最早 在 2015 年就有终止 fetch 请求的提案 issue 出现。在 fetch 规范之外也有许多解决这个问题的方案,像 cancelable-promises 和其他 hacks。
终于,通用的 AbortController 和 AbortSignal API 出来了。该 API 在 DOM 标准 中定义,而不是在语言规范中定义的。
AbortController是一个DOM API。MDN上对它的介绍是 AbortController接口表示一个控制器对象,允许根据需要终止一个或多个Web请求。
AbortController可以用在fetch和addEventListener,分别用来废弃请求和废弃监听器。
具体看官网:
https://developer.mozilla.org/zh-CN/docs/Web/API/AbortController/AbortController
https://caniuse.com/?search=AbortController
DOM 文档 中有这么一段话:
虽然 Promise 没有提供内置的终止算法(aborting mechanism),但是许多使用它们的 API 需要终止语义。AbortController 提供一个 abort() 方法来支持这些需求,这个方法用来切换相应 AbortSignal 对象的状态。希望支持终止功能的 API 可以接受 AbortSignal 对象,并基于其状态来确定执行流程。
AbortController由两部分构成:abort-signal和abort-controller,架构图如下:
红色部分是我们重点需要关注的部分,因为它们将直接体现在实际应用中
...
export?default?class?AbortSignal?extends?EventTarget<Events,?EventAttributes>?{
????/**
?????*?从abortedFlags中获取当前AbortSignal实例aborted状态
?????*/
????public?get?aborted():?boolean?{
????????const?aborted?=?abortedFlags.get(this)
????????if?(typeof?aborted?!==?"boolean")?{
????????????throw?new?TypeError(
????????????????`Expected?'this'?to?be?an?'AbortSignal'?object,?but?got?${
????????????????????this?===?null???"null"?:?typeof?this
????????????????}`,
????????????)
????????}
????????return?aborted
????}
}
//?设置abort自定义事件
defineEventAttribute(AbortSignal.prototype,?"abort")
...
/**
?*?创建一个AbortSinal实例,并设置aborted状态为false,存入abortedFlags中,同时绑定abort事件属性
?*/
export?function?createAbortSignal():?AbortSignal?{
????const?signal?=?Object.create(AbortSignal.prototype)
????EventTarget.call(signal)
????abortedFlags.set(signal,?false)
????return?signal
}
/**
?*?设置AbortSinal实例aborted状态为true,同时触发abort监听事件回调
?*/
export?function?abortSignal(signal:?AbortSignal):?void?{
????if?(abortedFlags.get(signal)?!==?false)?{
????????return
????}
????abortedFlags.set(signal,?true)
????signal.dispatchEvent<"abort">({?type:?"abort"?})
}
...
...
export?default?class?AbortController?{
????/**
?????*?构造函数,创建一个AbortSignal实例并存入signals中
?????*/
????public?constructor()?{
????????signals.set(this,?createAbortSignal())
????}
????/**
?????*?从signals中获取当前AbortSignal实例
?????*/
????public?get?signal():?AbortSignal?{
????????return?getSignal(this)
????}
????/**
?????*?先从signals中获取当前AbortSignal实例,然后设置实例aborted状态为true,触发abort监听回调事件
?????*/
????public?abort():?void?{
????????abortSignal(getSignal(this))
????}
}
...
众所周知,如果需要 removeEventListenr(type, callback), 它的callback必须和addEventListener是同一个函数引用,而在某些业务场景下,我们并不想多写函数可以改成用signal来控制。
例如,当在按钮鼠标时设置一个监听器,在监听器中再监听鼠标移动,鼠标松开关闭监听器:
??document.addEventListener('mousedown',?callback);
??document.addEventListener('mouseup',?callback2);
??function?callback?(e)?{
??????document.addEventListener('mousemove',??callback3);
???}
??function?callback2?(e)?{
?????document.removeEventListener('mousemove',?callback3);
??}
??
??function?callback3(event)?{}
如果改写成用AbortController怎么写呢?
????const?controller?=?new?AbortController();
????function?callback?(e)?{
??????document.addEventListener('mousemove',??(e)?=>?{
??????????
??????},{
???????????signal:?controller.signal??
??????});
???}
????document.addEventListener('mousedown',?callback);
????document.addEventListener('mouseup',?controller.abort);
每次请求,都会重新创建一个AbortSignal实例吗?
答:是的
signals和abortedFlags都是Map类型,每一个请求都会创建一个实例,随着时间的推移和请求的增多,如何防止缓存雪崩问题?
答:signals和abortedFlags准确的说是WeakMap类型,而WeakMap跟Map会有所区别,WeakMap的键只能是对象的引用,当垃圾回收机制执行时,会检测WeakMap的键是否被引用,若没有被引用,该键对会被删除,并自动回收,从而防止缓存雪崩的问题。
AbortSignal是如何具备监听事件能力的?
答:它本身并不具备事件处理能力,它继承了一个EventTarget类使其具备监听处理事件能力
参考文章:
一个可中断请求fetch的原理分析和应用 https://zhuanlan.zhihu.com/p/416572062
?[译] 使用 AbortController 终止 fetch 请求 https://juejin.cn/post/6844904072051425293
一个可中断请求fetch的原理分析和应用(之前的笔记) https://github.com/ctq123/blogs/issues/9
AbortController使用场景探索 https://www.jianshu.com/p/2f23c33e1922
转载本站文章《中断操作:AbortController学习笔记》, 请注明出处:https://www.zhoulujun.cn/html/webfront/SGML/html5/2022_0530_8824.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。