You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
如果SomeObject内部也有调用像fetch之类的内部 api 只需要把这个signal继续传递,则fetch也能被一起终止掉
如下是一个例子。展示了两种 signal 的用法。传递给内置 apifetch和检查signal状态执行一些操作
exportclassSomeObject{constructor(signal){this.signal=signal;// 执行一些操作例如发请求constp=fetch('/json',{ signal });}doComplexOperation(){if(this.signal.aborted){thrownewError(`thing stopped`);}for(leti=0;i<1_000_000;++i){// 执行复杂操作}}}
react hook 中的异步调用
我们通常会在useEffect中进行一些异步 api 调用。借助signal可以在下一次useEffect重新调用 api 的时候将前一次的调用终止
functionFooComponent({ something }){useEffect(()=>{constcontroller=newAbortController();const{ signal }=controller;constp=(async()=>{constj=awaitfetch(url+something,{ signal });})();return()=>controller.abort();},[something]);return<>...<>;
}
也可以封装一个useEffectAsync的 hook
functionuseEffectAsync(cb,dependence){constcontroller=newAbortController();const{ signal }=controller;useEffect(()=>{cb(signal);return()=>controller.abort();},dependence)}
今天介绍一个有用的 JavaScript api
AbortController
AbortController
是什么这个 api 简单来说就是可以提供一个能力给我们去提前终止一个 fetch 请求
一个终止 fetch 请求的 demo 如下:
提前终止后这个请求在 network 面板中的 status 显示为 canceled
在没有
AbortController
这个 api 之前,我们是没法去让浏览器提前去终止一个请求的。而有了这个 api 之后,浏览器就能提前终止请求进而节约一些用户带宽。除此之外,这个 api 也能给我们带来一些新的开发模式Controller 和 Signal
下面实例化了一个
AbortController
,它的signal
属性就是一个AbortSignal
controller.abort()
去终止它对应的signal
signal
本身是不能被直接终止的。可以将它传递给一些函数调用如 fetch 或者直接监听signal
的状态变化(可以通过signal.aborted
查看signal
的状态或者监听它的abort
事件)实际使用
普通对象中的终止
一些旧的 DOM api 是不支持
AbortSignal
。例如WebScocket
只提供了一个close
方法当我们无需使用时进行关闭。如果要使用AbortSignal
则可以类似以下的封装这个使用也很简单,但是需要注意的是如果
signal
已经终止的情况下是不会触发abort
事件,需要我们先进行一个判断是否signal
已经终止移除事件监听
我们经常需要在 js 中处理 dom 的监听和卸载工作。但是下面的例子由于事件监听和卸载传入的函数不是同一个引用时不会生效的
因此我们经常需要一些额外的代码去维护这个回调函数的引用的一致性。而有了
AbortSignal
之后我们就可以有一种的新的方式去实现因为
addEventListener
也能接收signal
属性的。我们最后只需要调用controller.abort()
,这个controller
的signal
传递的相关事件监听都会被自动相应卸载了构造器模式
在 JavaScript 中我们可能需要在对象中管理非常复杂的生命周期,如
WebSocket
。我们需要执行开启然后执行一系列逻辑后终止。可能我们会写以下代码也可以通过
AbortSignal
进行实现这能非常清晰地表示这个对象只能被执行一次,只能从开始到结束,而不能反过来。如果它终止了后想再次使用则需要再次创建一个对象
可以在很多地方共享一个
signal
。我们无需持有多个SomeObject
的实例。只需要调用controller.abort()
,这些SomeObject
的实例都能被终止掉如果
SomeObject
内部也有调用像fetch
之类的内部 api 只需要把这个signal
继续传递,则fetch
也能被一起终止掉如下是一个例子。展示了两种 signal 的用法。传递给内置 api
fetch
和检查signal
状态执行一些操作react hook 中的异步调用
我们通常会在
useEffect
中进行一些异步 api 调用。借助signal
可以在下一次useEffect
重新调用 api 的时候将前一次的调用终止也可以封装一个
useEffectAsync
的 hook一些有用的 AbortSignal 方法
AbortSignal.timeout(ms)
: 创建一个给定时间后终止的AbortSignal
AbortSignal.any(signals)
:创建一个AbortSignal
,如果传入的任一signal
终止了,这个返回的signal
也会被终止AbortSignal.throwIfAborted()
:如果signal
本身已经终止了,调用该方法会抛出执行abort(reason)
时指定的 reason 异常;否则只会静默执行这个方法目前不太容易 polyfill,但是可通过下面的工具函数实现
参考
https://whistlr.info/2022/abortcontroller-is-your-friend/
The text was updated successfully, but these errors were encountered: