五种异步实现方式对比
最近研究了一下 koa1 和 koa2 的源码,其中比较重要的就是中间件的流程控制,其中 koa1 是通过 generator 实现中间件流程控制,koa2 则是通过 async 函数,说起来利用 js 实现异步流程控制的方法也不少了,所以做一下总结对比。主要总结了五种实现方式:
- callback
- promise
- async
- thunk 版 generator
- promise 版 generator
具体代码可以看我在 codepen 上的 demo,分别打开各方法注释即可。
See the Pen async by newming (@newming) on CodePen.
下面简单看一下最终各中方式实现代码:
callback
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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
1 2 3 4 5 6 7 | (async function () { await promiseAnimate(ball1, 100) await promiseAnimate(ball2, 200) await promiseAnimate(ball3,150) await promiseAnimate(ball2,150) await promiseAnimate(ball1,150) })() |
基于 promise 的 generator 实现
1 2 3 4 5 6 7 8 | 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 实现
1 2 3 4 5 6 7 8 9 | 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 不错。
另外,能力有限,可能存在表达错误。另外具体各种方法实现,这里不做详细说明,可以参考下边提到的参考文章。
参考文章: