用JavaScript实现一个任务队列

用JavaScript实现一个任务队列。


前言

头条一面的题,有思路,但是JavaScript Promise用的不够熟练,记录一下。

题目

给定一个API,实现对应的功能。

API

给定如下接口,请实现一个任务队列。效果是task方法用于注册任务,start函数调用后,1s后打印1,再过2s后打印2,再过3秒后打印3。

1
2
3
4
5
6
7
8
9
10
11
new Queue()
.task(1000, () => {
console.log(1);
})
.task(2000, () => {
console.log(2);
})
.task(3000, () => {
console.log(3);
})
.start();

思路

0x1

首先task方法仅仅是注册,因此需要将注册的内容保存下来。

定义一个如下对象用于保存注册的任务:

1
2
3
4
this.tasks = [{
delay:1,
callback:()=>{},
}];

0x2

然后可以链式调用task方法,因此其返回值就是this

1
2
3
4
5
task(delay, callback) {
this.tasks.push({ delay, callback });
// console.log(callback)
return this;
}

0x3

最后是关键部分,如何把任务给连接起来并开启队列执行。

执行顺序应该是这样的

1
2
3
4
5
6
task1设置
->1s...task1运行
->task2在task1回调函数执行后设置
->2s...task2运行
->task3在task2回调函数执行后设置
->3s...task3运行

我们创建一个Promise对象,添加一个定时器,在setTimeout回调函数中执行完注册的callback后resolve。这样我就可以在这个Promise对象的then方法中添加下一个定时器。

实现

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Queue {
constructor() {
this.tasks = [];
}
task(delay, callback) {
this.tasks.push({ delay, callback });
// console.log(callback)
return this;
}
start() {
if (this.task.length === 0) return;
let cur = this.tasks.shift();
let func = new Promise((resolve, reject) => {
console.log("starting......");

setTimeout(() => {
cur.callback();
resolve();
}, cur.delay);
});
while (this.tasks.length !== 0) {
const element = this.tasks.shift();

func = func.then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
element.callback();
resolve();
}, element.delay);
})
});

}
func.then(() => {
console.log("ending.....");

})
}

}

new Queue()
.task(1000, () => {
console.log(1);
})
.task(2000, () => {
console.log(2);
})
.task(3000, () => {
console.log(3);
})
.start();

总结

Promise对象的使用不够熟练,后续会继续深入学习,敬请期待。