如何设计Nodejs的可取消任务
前言
在前两篇文章中, 我们分别介绍了如何设计定时任务,重试任务,假如你还没看过这两篇文章,可以点击下方的链接来阅读。
今天我们来介绍,如何设计可取消任务:
各位读者要是觉得我的文章对你有一点点帮助的话,麻烦点赞收藏,写作不易,你的支持就是我更新的动力。谢谢!!
什么是可取消任务
在 Node.js 中,可取消任务指的是可以在执行过程中通过某种方式取消的任务。
为什么你需要关注可取消任务
有很多的原因使得创建可取消任务在前端开发中和Nodejs开发中变成有意义:
-
避免资源浪费:如果一个任务执行时间过长,就会造成资源的浪费,这个时候就可以取消这个任务。例如:一个在断网环境下不断重试的api请求。同样的,假如一个任务突然间变得没有意义了,也需要取消,比如说这个任务被最新的任务抢占。
-
用户体验:面对漫长的等待过程,用户可以使用取消功能,取消任务,进而提升用户体验。
如何设计可取消任务
预备知识-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();
}
}
代码解释
-
参数设计:我们必须将signal作为参数传入函数体内。
-
提前判断是否被取消:有时候我们的函数在执行之前,其实已经被取消了,所以在获取参数后,立即判断是否被取消。这样避免了多余的工作。
-
监听取消事件:这个事件的监听工作应该紧接着前面的代码,这样保证了,在业务代码执行之前,我们能快速取消
-
设计业务代码
对于异步代码:向异步任务中传入signal。目前浏览器和Nodejs的原生api开始支持signal参数了。异步任务之间可以使用
signal.aborted === true
来防止执行后续对于同步代码:使用
signal.aborted === true
来防止执行后续 -
当代码运行到最后后,调用
taskDone.abort();
来清除 signal上的事件监听器,避免内存泄漏
小结
设计一个合适的可取消任务,关键是设计业务代码的思路:
对于同步代码:
我们只能使用signal.aborted === true
判断语句来决定执不执行后面的代码。
对于异步代码:
-
异步代码之间:我们考虑是否用
signal.aborted === true
判断语句来决定执不执行后面的代码。 -
对于单个异步代码:
-
支持signal的情况下:可以传入signal来作为粘合剂。
-
不支持signal的情况下:
- 其他取消机制:我们就在
signal.addEventListener('abort',() => {} )
的回调中使用其他取消机制处理。 - 没有取消机制:没办法直接让它执行到下一个signal.aborted === true`判断语句来决定执不执行后面的代码
- 其他取消机制:我们就在
-
总结
这篇文章的主要是提出了一种设计Nodejs的可取消任务的代码框架,并且对关键的实现细节做出了说明。设计小结部分是本文的核心,分类讨论每种情况下,我们应该如何使用相应的取消机制,来实现代码的取消。这部分是这篇文章的核心,希望对各位设计api时候有帮助。
最后的话
学习最重要的是有反馈,工作了一年半,感觉到达到了瓶颈,目前就业情况不太乐观。希望借助这个平台和大家交流技术,突破职业平台期。
各位读者要是觉得我的文章对你有一点点帮助的话,麻烦点赞收藏,写作不易,你的支持就是我更新的动力。谢谢!!
转载自:https://juejin.cn/post/7185193457072209979