题目:红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯不断交替重复亮灯?(用Promse实现)
为了方便演示控制台里执行代码,增加额外的条件:只需要循环3次。
1. Promise最常规实现
function red () {
console.log('red')
}
function green () {
console.log('green')
}
function yellow() {
console.log('yellow')
}
var tic = function(timmer, cb){
return new Promise(function(resolve, reject) {
cb();
setTimeout(resolve, timmer);
});
}
var round = 0;
var maxRound = 3;
;(function step() {
if(++round > maxRound ) {
return;
}
console.log(`Round ${round}`)
tic(3000, red)
.then(function() {
return tic(2000, green)
})
.then(function() {
return tic(1000, yellow)
})
.then(step)
})()
2. 使用 Array.prototype.reduce
方法优化调用方式
题目本质就是元素前后存在依赖的任务,可以采用Array.prototype.reduce
方法优化调用方式。
var round = 0;
var maxRound = 3;
;(function step(){
if(++round > maxRound) {
return;
}
console.log(`Round ${round}`);
[red, green, yellow, step].reduce((prev, cb, index, arr) => {
return prev.then(() => {
return tic(1000 * (arr.length - index - 1), cb)
})
}, Promise.resolve())
})()
3. 基于Generator函数的实现
var round = 0;
var maxRound = 3;
function* gen() {
yield tic(3000,red);
yield tic(2000, green);
yield tic(1000, yellow)
}
(function step() {
if(++round > maxRound) {
return;
}
console.log(`Round ${round}`);
var g = gen();
(function next(){
var result = g.next();
if(result.done) {
step();
} else {
result.value.then(next)
}
})()
})();
- 果然使用
Gengerator
函数控制异步流程确实比较烧脑,还是async/await
吧
4. 基于async/await的实现
// 重新定义了tic函数
var tic = function(timmer, cb){
return () => new Promise(function(resolve, reject) {
cb();
setTimeout(resolve, timmer);
});
}
var round = 0;
var maxRound = 3;
(async function step() {
if(++round > maxRound) {
return;
}
console.log(`Round ${round}`);
;[tic(3000,red), tic(2000, green), tic(1000, yellow), step]
.reduce(async (preTask, currentTaskFunc) => {
await preTask; // 等上一个任务结束,再执行当前任务
await currentTaskFunc(); // 或则 `return currentTaskFunc()`
}, void 0)
})()
reduce
方法的第二个实参传递是undefined
, 再加上第一个实参是个async
函数并且返回值也是undefined
,所以await preTask
的值是undefined
。
5. 基于callback
实现
主要是看评论区里有人提供了callback
方案,想着跟Expressjs的中间件函数调用类似,自己也写个callback方式的:
function red (next) {
console.log('red')
setTimeout(next, 3000)
}
function green (next) {
console.log('green')
setTimeout(next, 2000)
}
function yellow(next) {
console.log('yellow')
setTimeout(next, 1000)
}
var round = 0;
var maxRound = 3;
;(function step() {
if(++round > maxRound ) {
return;
}
console.log(`Round ${round}`)
var tasks = [red, green, yellow, step]
;(function next() {
var task = tasks.shift();
task(next);
})()
})()
写法2:
var round = 0;
var maxRound = 3;
var tasks = [red, green, yellow, step];
function step() {
if(++round > maxRound ) {
return;
}
console.log(`Round ${round}`)
var index = 0;
;(function next() {
var currentTask = tasks[index++];
currentTask(next);
})()
}
step();
- 利用索引控制轮询的任务;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。