最近研究了一下 koa1 和 koa2 的源码,其中比较重要的就是中间件的流程控制,其中 koa1 是通过 generator 实现中间件流程控制,koa2 则是通过 async 函数,说起来利用 js 实现异步流程控制的方法也不少了,所以做一下总结对比。主要总结了五种实现方式:
- callback
- promise
- async
- thunk 版 generator
- promise 版 generator
具体代码可以看我在 codepen 上的 demo,分别打开各方法注释即可。整体代码如下:
async
五种异步流程控制的实现
下面简单看一下最终各中方式实现代码:
callback
animate(ball1, 100, function () {
animate(ball2, 200, function () {
animate(ball3, 300, function () {
animate(ball3, 150, function () {
animate(ball2, 150, function () {
animate(ball1, 150, function () {
})
})
})
})
})
})
promise
promiseAnimate(ball1,100)
.then(function () {
return promiseAnimate(ball2,200)
})
.then(function () {
return promiseAnimate(ball3,300)
})
.then(function () {
return promiseAnimate(ball3,150)
})
.then(function () {
return promiseAnimate(ball2,150)
})
.then(function () {
return promiseAnimate(ball1,150)
})
async
(async function () {
await promiseAnimate(ball1, 100)
await promiseAnimate(ball2, 200)
await promiseAnimate(ball3,150)
await promiseAnimate(ball2,150)
await promiseAnimate(ball1,150)
})()
基于 promise 的 generator 实现
var movePromise = function* (){
yield promiseAnimate(ball1, 100);
yield promiseAnimate(ball2, 200);
yield promiseAnimate(ball3, 150);
yield promiseAnimate(ball2, 150);
yield promiseAnimate(ball1, 150);
};
run(movemovePromise) // 需要自己实现 run 函数
基于 thunk 的 generator 实现
var moveThunk = function* (){
yield animateThunk(ball1, 100)
yield animateThunk(ball2, 200)
yield animateThunk(ball3, 150)
yield animateThunk(ball2, 150)
yield animateThunk(ball1, 150)
};
run(moveThunk) // 同样需要自己 run 函数
总结
callback 写法最不直观,当有多个连续执行异步操作任务时,容易造成回调地狱。其余四种都是同步写法实现异步流程控制,其中 async 函数相当于自动执行的 Promise 以及后边的 generator 函数,如果使用 generator,需要自己实现一个 run 函数来进行自动化执行,这里就要提到著名的 co 库。总的来说还是 async 不错。
另外,能力有限,可能存在表达错误。另外具体各种方法实现,这里不做详细说明,可以参考下边提到的参考文章。
参考文章:
- 阮一峰 es6 入门
- purplebamboo blog