如何设计Nodejs的可取消任务


highlight: a11y-dark
theme: channing-cyan

前言

在前两篇文章中, 我们分别介绍了如何设计定时任务,重试任务,假如你还没看过这两篇文章,可以点击下方的链接来阅读。

如何设计Nodejs的定时任务

如何设计Nodejs的重试任务

今天我们来介绍,如何设计可取消任务:

如何设计Nodejs的可取消任务

各位读者要是觉得我的文章对你有一点点帮助的话,麻烦点赞收藏,写作不易,你的支持就是我更新的动力。谢谢!!

什么是可取消任务

在 Node.js 中,可取消任务指的是可以在执行过程中通过某种方式取消的任务。

为什么你需要关注可取消任务

有很多的原因使得创建可取消任务在前端开发中和Nodejs开发中变成有意义:

  1. 避免资源浪费:如果一个任务执行时间过长,就会造成资源的浪费,这个时候就可以取消这个任务。例如:一个在断网环境下不断重试的api请求。同样的,假如一个任务突然间变得没有意义了,也需要取消,比如说这个任务被最新的任务抢占。

  2. 用户体验:面对漫长的等待过程,用户可以使用取消功能,取消任务,进而提升用户体验。

如何设计可取消任务

预备知识-AbortController & AbortSignal apis

具体关于AbortController的知识我推荐大家可以看看这篇文章

目前,无论是浏览器端还是Nodejs端,AbortController 和 AbortSignal APIs 已经成为了标准的取消机制。

因此,我们下面仅仅讨论使用AbortController 和 AbortSignal APIs 设计可以取消的任务。

下面通过一段代码来见到说明一下这个api。


const controller = new AbortController(); 

controller.signal.addEventListener('abort', () => { 
    console.log('在这里执行取消操作!!!');
}, { once: true }); 

controller.abort();

首先,我们通过调用 new AbortController() 创建了一个 AbortController 对象。

然后,controller.signal.addEventListener('abort') 注册了一个监听器函数。

最后,当我们调用controller.abort()的时候,就会触发abort事件,然后就触发了可取消操作。

注意,我们调用addEventListener 时传入了 { once: true } 参数,表示该监听器函数只会被调用一次。

如果没有传入这个参数,那么在 abort 事件再次发生时,监听器函数也会再次被调用。这个行为可能导致内存泄漏。 如果你不清楚为什么这里有内存泄漏的风险的话,可以关注我,以后我会有文章介绍。

如何设计可取消任务

代码框架

经过简单得热身后,我们终于要设计可取消任务了,下面贴出我参看得框架代码:

async function cancelJob(options) {
  
  // 参数设计
  const { signal } = options; 
  
  // 提前判断是否被取消
  if (signal.aborted === true) {
      throw new Error('任务取消');
  }
    
  
  const taskDone = new AbortController();
  
  // 监听取消事件
  signal.addEventListener('abort', () => {
    console.log('这里可以尝试取消异步任务')
  }, {
    once: true,
    signal: taskDone.signal
  });
  
  // 设计业务代码
  try {
    // 向异步任务中传入signal
      await task(signal)
    // 隔断同步代码
      if (signal.aborted === true) {
          throw new Error('任务取消');
      }
    // 异步任务。。。
        await task(signal)
  } finally {
    // 使用abort来避免signal.addEventListener('abort') 内存泄漏
    taskDone.abort();
  }
}

代码解释

  1. 参数设计:我们必须将signal作为参数传入函数体内。

  2. 提前判断是否被取消:有时候我们的函数在执行之前,其实已经被取消了,所以在获取参数后,立即判断是否被取消。这样避免了多余的工作。

  3. 监听取消事件:这个事件的监听工作应该紧接着前面的代码,这样保证了,在业务代码执行之前,我们能快速取消

  4. 设计业务代码

    对于异步代码:向异步任务中传入signal。目前浏览器和Nodejs的原生api开始支持signal参数了。异步任务之间可以使用signal.aborted === true 来防止执行后续

    对于同步代码:使用signal.aborted === true 来防止执行后续

  5. 当代码运行到最后后,调用 taskDone.abort(); 来清除 signal上的事件监听器,避免内存泄漏

小结

设计一个合适的可取消任务,关键是设计业务代码的思路:

对于同步代码:

我们只能使用signal.aborted === true判断语句来决定执不执行后面的代码。

对于异步代码:

  1. 异步代码之间:我们考虑是否用signal.aborted === true判断语句来决定执不执行后面的代码。

  2. 对于单个异步代码:

    1. 支持signal的情况下:可以传入signal来作为粘合剂。

    2. 不支持signal的情况下:

      1. 其他取消机制:我们就在signal.addEventListener('abort',() => {} ) 的回调中使用其他取消机制处理。
      2. 没有取消机制:没办法直接让它执行到下一个signal.aborted === true`判断语句来决定执不执行后面的代码

总结

这篇文章的主要是提出了一种设计Nodejs的可取消任务的代码框架,并且对关键的实现细节做出了说明。设计小结部分是本文的核心,分类讨论每种情况下,我们应该如何使用相应的取消机制,来实现代码的取消。这部分是这篇文章的核心,希望对各位设计api时候有帮助。

最后的话

学习最重要的是有反馈,工作了一年半,感觉到达到了瓶颈,目前就业情况不太乐观。希望借助这个平台和大家交流技术,突破职业平台期。

各位读者要是觉得我的文章对你有一点点帮助的话,麻烦点赞收藏,写作不易,你的支持就是我更新的动力。谢谢!!

exported (9).jpg

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容