业务中经常会有一些批量操作的任务,比如使用 JavaScript 预加载一组图片,批量上传一些资源。如果这些任务一次性启动,势必会消耗很多资源和带宽。理想的做法应该对这些任务进行限制,比如一次只跑几个,当其中一些任务完成后,再添加新的任务到队列。

总的来说,我们需要这样一个服务,它提供一个添加任务的方法,内部将添加的方法维护在一个数组。然后根据设置的阈值,即同时可跑的任务数,来执行这些任务。

同时为了打日志方便,注册的任务可指定一个名称,所以一个任务的类型看起来应该像这样:

type Task<T> = {
name?: string;
fn: () => Promise<T>;
};

其中 name 方便调试,fn 便是需要执行的任务,它应该是一个比较耗时的异步任务,所以调用后返回 Promise。

运行任务的服务:

export class TaskRunner {
private queue: Task<any>[] = [];
private activeTaskNum: number = 0; constructor(private limit = 5, public debug = false) {

if (limit < 1) {

throw new Error("limit must be interger greater then 1");

}

} public addTask<T>(task: Task<T>) {

task.name ? task.name : task.fn.name || this.queue.length || "";

this.queue.push(task);

this.runTask();

} private execute<T>(task: Task<T>) {

this.log(</span>running ${<span class="pl-smi">task</span>.<span class="pl-c1">name</span>}<span class="pl-pds">);

return task

.fn()

.then(ressult => {

this.log(</span>task ${<span class="pl-smi">task</span>.<span class="pl-c1">name</span>} finished<span class="pl-pds">);

return ressult;

})

.catch(error => {

this.log(</span>${<span class="pl-smi">task</span>.<span class="pl-c1">name</span>} failed<span class="pl-pds">);

throw error;

})

.finally(() => {

this.activeTaskNum--;

this.runTask();

});

} private runTask() {

while (this.activeTaskNum < this.limit && this.queue.length > 0) {

const task = this.queue.shift();

this.activeTaskNum++;

this.execute(task!);

}

} private log(msg: string) {

if (this.debug) {

console.info(</span>[TaskRunner] ${<span class="pl-smi">msg</span>}<span class="pl-pds">);

}

}

}

因为任务可以动态添加,所以在添加完任务的方法 addTask() 里就启动任务队列的执行 runTask(),无须外部显式触发。

测试上面的代码:

import { TaskRunner } from "./taskRunner";

const runner = new TaskRunner(3, true);

function taskGenerator(taskName: string, time: number) {

return {

name: taskName,

fn: () =>

new Promise<string>((resolve, _reject) => {

setTimeout(() => {

resolve(</span>result for task ${<span class="pl-smi">taskName</span>}<span class="pl-pds">);

}, time);

})

};

} const errorTask = {

name: "errroTask",

fn: () =>

new Promise<string>((_resolve, reject) => {

setTimeout(() => {

reject("errorTask failed");

}, 3000);

})

}; [errorTask]

.concat(

[...new Array(5).keys()].map((_value, index) =>

taskGenerator(String(index), Math.random() * 10000 + 1000)

)

)

.forEach(task => runner.addTask(task));

这里生成了 5 个任务,每个任务的耗时是随机的 1s ~ 10s。同时添加一个了个直接 reject 的任务来模拟任务失败时,不会影响其他任务的执行。

完整的代码移步 GitHub 仓库 wayou/task-runner

相关资源

TypeScript 实现任务队列的更多相关文章

  1. 异步任务队列Celery在Django中的使用

    前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...

  2. TypeScript: Angular 2 的秘密武器(译)

    本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch?v=e3djIqAGqZo 开场白 开场白主要分为三部分: 感谢了 ...

  3. TypeScript为Zepto编写LazyLoad插件

    平时项目中使用的全部是jQuery框架,但是对于做webapp来说jQuery太过于庞大,当然你可以选择jQuery 2.*针对移动端的版本. 这里我采用移动端使用率比较多的zepto框架,他跟jqu ...

  4. TypeScript Vs2013 下提示Can not compile modules unless '--module' flag is provided

    VS在开发TypeScript程序时候,如果import了模块有的时候会有如下提示: 这种情况下,只需要对当前TypeScript项目生成设置为AMD规范即可!

  5. TypeScript

    TypeScript: Angular 2 的秘密武器(译)   本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch? ...

  6. 打造TypeScript的Visual Studio Code开发环境

    打造TypeScript的Visual Studio Code开发环境 本文转自:https://zhuanlan.zhihu.com/p/21611724 作者: 2gua TypeScript是由 ...

  7. 转职成为TypeScript程序员的参考手册

    写在前面 作者并没有任何可以作为背书的履历来证明自己写作这份手册的分量. 其内容大都来自于TypeScript官方资料或者搜索引擎获得,期间掺杂少量作者的私见,并会标明. 大部分内容来自于http:/ ...

  8. 通过IEnumerable和IDisposable实现可暂停和取消的任务队列

    一般来说,软件中总会有一些长时间的操作,这类操作包括下载文件,转储数据库,或者处理复杂的运算. 一种处理做法是,在主界面上提示正在操作中,有进度条,其他部分不可用.这里带来很大的问题, 使用者不知道到 ...

  9. Webstorm编译TypeScript

    下载webstorm 下载node.js编译器npm   Webstorm的安装很简单.但如果没有Java For Mac 环境打开Webstorm时会有提示,点击提示会跳转下载链接,下载安装就好. ...

随机推荐

  1. Mybatis 系列1

    第一篇教程, 就先简单地写个demo, 一起来认识一下mybatis吧. 为了方便,我使用了maven, 至于maven怎么使用, 我就不做介绍了.没用过maven的, 也不影响阅读. 一.Mybat ...

  2. orderBy新写法

    通常,我们处理排序规则的处理方法是在sql 语句中order by create_time desc, 但是这时我们需要从控制器中一步步找到该方法,操作多. 我们试着将业务逻辑拆分到控制器 中, 把排 ...

  3. jtds驱动更新对一个老问题的解决

    07年年末的一篇blog: 以前网站做初期开发时,有一个问题:hibernate下text大字符串读取时出这个异常:JDBCExceptionReporter - The amount of data ...

  4. Error:unsupported class file version 52.0问题的解决

    这个问题主要的原因是依赖包的编译版本比主程序的编译版本高,导致主程序无法正常编译或运行,解决这个问题无非两招: 1.提升主程序的编译器版本,用最新的编译器编译主程序,这样就可以兼容那个依赖包 2.降低 ...

  5. All is Over

    Noip2017结束,AFO.WC2017上神犇们唱的膜你抄   就是退役的背景音乐了 不管以后何去何从,Oier的生涯对我来说已经终了,找个日子好好回忆一下这么多年的Oi时光,然后写篇博文祭奠 自此 ...

  6. lodash中Collection部分所有方法的总结

    总结一下lodash中Collection的所有的方法,方便对比记忆,也便于使用时候查找. 1.    判断是否符合条件:返回bool: a)  every: 判断每一值是不是都符合条件: 通过 pr ...

  7. Windows下的OpenCVSharp配置

    OPenCvSharp是OpenCV的Net Warpper,应用最新的OpenCV库开发,目前放在github.. 本人认为OpenCvSharp比EmguCV使用起来更为方便,因为函数更接近于原生 ...

  8. 微信小程序函数调用监控

    微信小程序之无埋点函数调用监控 有时候,面对一个bug,左思右想就是无法理解为什么. 我就有过这样的经历,耗时整个一个晚上,后来还是放弃了.不得不在所有可能的点都加上日志,部署等待再次报错,真的很让人 ...

  9. Oracle-11:联合查询

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 联合查询的实际上的意义就是从俩个结果集中拿有特定联系的结果封装为一个结果集 数据库脚本给放一份,供测试使用 c ...

  10. .Net Core vs .Net Framework 如何为一个应用程序选择一个运行时

    .Net Core是下一件大事吗?我已经使用了一段时间了,我倾向认为它是.事实上,我们推测,在2018年,对这项技术熟练的开发人员将会有巨大的需求.但是它和.Net Framework的区别是什么?你 ...