这个库名字叫 easytask,它的作用是能够让同步或异步任务写起来更方便,解决这几个痛点,我例举几个:
1、当页面弹窗比较多的时候,如何判断该弹哪一个弹窗,有的弹窗条件是同步方法,比如通过存储在 localstorage 的一个 key 来判断(同步);有的需用通过接口判断(异步);面对这种异步与同步混合的任务你该如何做?停顿几秒,思考一下你以前是如何解决这类问题的。
2、网络请求依赖,比如登录后,获取用户信息,然后通过不同的用户显示不同的页面逻辑,3个网络请求,如何做到串行执行,并且后一个网络请求需要依赖前一个网络请求的结果。停顿几秒,思考一下你以前是如何解决这类问题的。
3、有 10 个网络请求,如何控制它的并发数,一次只能执行两个任务,等所有的任务执行完后把所有的结果返回。
流水线控制任务的串行执行
以上这几个例子,最简单的方法就是各种 if - else 判断,然后满足条件后执行其它任务,但其实可以把以上这些过程进行「抽象化」。我们看下解决串行任务时,easytask 做的事情:
流水线,可以解决网络串行执行依赖问题和任务串行执行:
创建一个流水线,并初始化一个数据 data,这个 data 在每个任务中可以使用
let data = {};
let pipeline = new Pipeline(data);
添加一个同步任务,如果需要执行下一个任务,需要手动调用 next 函数
pipeline.use((data, next) => {
doSomething();
// run next task
next();
});
添加一个异步任务,并在 data 中添加一个数据,这样下一个任务可以直接使用这个数据
pipeline.use((data, next) => {
setTimeout(() => {
// you can change data, add property taskId to data
data.taskId = 'everydata';
next();
}, 200);
});
再添加一个异步任务
// add sync task to pipeline
pipeline.use(function (data, next) {
if (data.taskId) {
// find the task, stop run
}
else {
next();
}
});
开启任务执行,所有的任务执行顺序是按照添加顺序一个一个执行,下一个任务是否要执行,完全由使用者通过 next 函数来控制
// the task begin run
pipeline.run();
队列控制任务的串行与并行执行
队列与流水线的主要区别是,队列中的任务是自动执行的,而流水线的下一个任务执行需要使用者调用 next 函数:
Queue 中提供了 3 个函数:
第 1 个 queue.race:
race(this: any, tasks: Task[]): Promise<any>;
任务串行执行,只要有一个任务 resolve 一个真值,那么整个队列将停止,返回一个 Promise 对象,你可以这样使用:
一个同步任务,函数的返回值为任意对象,为真时队列将停止执行:
const everyDay = (data) => {
return false;
};
一个异步任务,需要返回一个 Promise,resolve 为真时,队列将停止执行:
const newUser = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('new user');
}, 100);
});
};
一个异步任务,需要返回一个 Promise
const vip = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('vip');
}, 10);
});
};
创建一个队列,并执行这些任务,第2个任务返回一个真值,第 2 个任务获胜
let queue = new Queue();
// 创建一个任务数组
let tasks = [everyDay, newUser, vip];
// 开始执行任务
queue.race(tasks).then(res => {
// 第2个任务返回一个真值,第 2 个任务获胜
console.log('queue finished =', res);
}).catch(error => {
console.log('error = ', error);
});
第 2 个 queue.serial:
serial(this: any, tasks: Task[]): Promise<any>;
和流水线差不多,任务串行执行,知道所有的任务执行完才队列才会停止,并返回每个任务执行的结果。
一个同步任务,函数的返回值为任意对象:
const everyDay = (data) => {
return false;
};
一个异步任务,需要返回一个 Promise
const newUser = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('new user');
}, 100);
});
};
一个异步任务,需要返回一个 Promise
const vip = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('vip');
}, 10);
});
};
创建一个队列,并执行这些任务
let queue = new Queue();
let tasks = [everyDay, newUser, vip];
queue.serial(tasks).then(res => {
// res {
// 0: false,
// 1: new user,
// 2: vip
// }
console.log('queue finished =', res);
}).catch(error => {
console.log('error = ', error);
});
第 3 个 queue.parallel:
parallel(this: any, tasks: Task[], limit: number): Promise<any>;
队列中的任务并行执行,通过参数控制并发数:
一个同步任务,函数的返回值为任意对象:
const everyDay = (data) => {
return false;
};
一个异步任务,需要返回一个 Promise
const newUser = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('new user');
}, 100);
});
};
一个异步任务,需要返回一个 Promise
const vip = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('vip');
}, 10);
});
};
创建一个队列,并执行这些任务,一次只能并发执行两个任务
let queue = new Queue();
let tasks = [everyDay, newUser, vip];
queue.parallel(tasks, 2).then(res => {
// res {
// 0: false,
// 1: new user,
// 2: vip
// }
console.log('queue finished =', res);
}).catch(error => {
console.log('error = ', error);
});
以上是我为解决此类问题创建的一个开源库,如果有不妥的地方,欢迎大家吐槽,代码已提交,如果未收到任何人的吐槽,我将发布一个 npm 包。单测覆盖 100%,可放心使用,有问题肯定会及时响应。
项目地址:https://github.com/lefex/easytask
长按关注
素燕《前端小课》
帮助 10W 人入门并进阶前端
官网:https://lefex.gitee.io/