最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用 AbortController 取消 Fetch 请求和事件监听

    正文概述 掘金(B2D1)   2021-04-25   734

    前言

    AbortController 是一个控制器对象,你可以通过 new 构造函数的形式返回一个 AbortSignal 对象:

    const controller = new AbortController();
    
    • 它有一个方法 abort(),用于触发 abort 事件
    • 和单个属性 signal,可以在该属性上设置 abort 事件监听
    controller.signal.onabort = () => {};
    
    controller.signal.addEventListener("abort", () => {});
    

    controller.abort() 被调用时:

    • controller.signal 就会触发 abort 事件
    • controller.signal.aborted 属性从 false 变为 true

    了解前置知识后,看一下实际应用的场景。

    取消 Fetch 请求

    在没有 Fetch API 之前,一般通过 XMLHttpRequest 来实现数据更新,当我们发出请求后想临时取消,可以调用 XMLHttpRequest.abort() 方法来终止该请求。

    有了 AbortController,同样可以实现取消 Fetch 请求。

    const controller = new AbortController();
    const signal = controller.signal;
    
    fetch("/", { signal }).catch(err => {
      console.log(err); // DOMException: The user aborted a request.
      console.log("aborted:", signal.aborted); // aborted: true
    });
    
    controller.abort();
    

    使用 AbortController 取消 Fetch 请求和事件监听

    移除事件监听

    以往,我们通过 EventTarget.addEventListener() 来为一个 DOM、document 或 window 添加事件监听。

    它的函数签名如下:

    target.addEventListener(type, listener);
    target.addEventListener(type, listener, options);
    target.addEventListener(type, listener, useCapture);
    

    options 是一个可选参数对象,它包含了以下属性来决定事件触发的行为:

    • capture: boolean,如果是 true,表示 listener 会在指定 type 事件类型的 捕获 阶段触发。false 则为 冒泡 阶段
    • once: boolean,表示 listener 在添加之后最多只调用一次。如果是 true, listener 会在其被调用之后自动移除
    • passive: boolean,设置为 true 时,表示 listener 永远不会调用 preventDefault(),用于优化页面的滚动性能

    当不再需要事件监听时,调用 EventTarget.removeEventListener() 来移除事件监听,但要保证 参数和添加监听时是一致的,即 type 事件类型必须是同一字符串,listener 回调函数必须是同一个函数引用,options 对象必须属性相同。

    const btn = document.getElementsByTagName("button")[0];
    
    btn.addEventListener("click", () => console.log("button clicked"), {
      capture: true,
    });
    
    // Doesn't work, because has different callback functions
    btn.removeEventListener("click", () => console.log("button clicked"), {
      capture: true,
    });
    

    在 Chrome 88 发布时,添加了一个 AbortSignal in addEventListener 的新特性,它允许 AbortController 实例的 signal 属性传入 addEventListener() 的 options 对象,一旦调用实例的 abort() 方法,就会移除对应的事件监听。

    这意味着开发者摆脱了调用 removeEventListener() 时繁琐的参数困境,只需使用 abort() 方法,既减少了代码量,又一目了然。

    下面的代码实现了 "click once" 的效果,实测(Chrome 90)运行成功。

    const controller = new AbortController();
    const signal = controller.signal;
    const btn = document.getElementsByTagName("button")[0];
    
    const handle = () => {
      console.log("button clicked");
      controller.abort();
    };
    
    btn.addEventListener("click", handle, {
      capture: true,
      signal,
    });
    
    // equals to
    // btn.addEventListener("click", handle, { once: true });
    

    其他应用场景

    取消定时器 - 初级版:

    function timeout(duration, signal) {
      return new Promise((resolve, reject) => {
        const handle = setTimeout(resolve, duration);
        signal.onabort = () => {
          clearTimeout(handle);
          reject(new Error("The timeout was aborted"));
        };
      });
    }
    
    const controller = new AbortController();
    
    timeout(10000, controller.signal).catch(err => console.log(err));
    
    controller.abort();
    

    取消定时器 - 高级版:

    import { setTimeout } from "timers/promises";
    
    const ac = new AbortController();
    const signal = ac.signal;
    
    setTimeout(1000, "foobar", { signal })
      .then(console.log)
      .catch(err => {
        if (err.name === "AbortError") console.log("The timeout was aborted");
      });
    
    ac.abort();
    

    Reference

    • MDN - EventTarget.addEventListener()

    • CSS - TRICKS - Using AbortController as an Alternative for Removing Event Listeners

    • WHATWG living standard - AbortController

    • nodejs - Cancelling timers


    起源地下载网 » 使用 AbortController 取消 Fetch 请求和事件监听

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元