浅谈 co 库
最近在写一个静态博客框架. 但不同于 hexo 之类的, 框架本身提供了博客书写和管理功能. 后端同样使用了 Koa2 来做,
归功于 Arch, 我已经在使用 Node 7.2 了, 不过好像默认还是不能支持 async
和 await
, 经查发现是要输入参数开启的=.=. 不过当时第一时间并没有想说去加参数解决, 而是使用了 co
这个库… 虽然也可以用 babel
, 但是通过 babel
运行代码很难调试.
co
用起来其实和 async
差不多, 甚至一些地方更简洁, 比如他可以 yield 一个 Promise 数组. 而 async
则只能 await
一个 Promise.all. 其实归根就是 co
进行了一个隐性的转换.co
内可以直接 yeild
一个数组或对象, co
会自动把数组或对象里面的所有值尝试转为 Promise 并包装在 Promise.all 中返回.
|
|
而 async
要处理多个异步的并行操作, 只能把这些操作手动放入 Promise.all 返回. 即:
|
|
草案还有一个 await*
, 这个也是最近才注意到的, 使用 await*
就可以这样写了:
|
|
然而草案并不推荐 await*
, 目前 Node 7.2 也不支持 await*
, 不过 babel 支持 ~
co
的代码其实刚接触异步的时候我就去看了下, 当然当时肯定看不懂. 不过现在回过来看感觉很明了. 其实 co
的实现思路也很简单. co
接收一个 generator, 然后他就可以自动的运行这个 generator 而不需要手动的 yield
.
co
的实现简要过程:
- 接受一个 generator
- generator 封装进 promise
- 调用该 generator
- 判断是否可以 next, 如果不可以直接 resolve, 否则下一步
- 执行 next 操作并取得 next 后的 generator
- 判断是否已经 done, 如果是则直接 resolve, 否则下一步
- 递归调用第 2 步
参考以上自己可以结合 co 源码看下. 看看是不是就这么回事.
co
内部有一个方法来对 yield
后面的东西进行处理:
|
|
我觉得 yield
可以接一个数组这点很好, 相比起来 async
则要接一个 Promise.all 来处理多个异步的同时运行处理.
|
|
另外, 它也可以接收对象, 这个不是普通的对象, 这个对象里面的值也会执行上面的 toPromise 方法, 然后用 Promise.all 包装后返回.
这样来看其实 co
除了语义没有 async-await
好其实很多方面都更胜一筹.
最后还有一个 co.wrap
方法, 它用来封装一个 generator.
|
|
其实就是把 generator 放在一个方法里面, 当这个方法调用时立即通过 co
自动启动该 generator 而已. 把这个方法返回了用于导出或者其他用途都可以咯.
真的短小精悍… 膜拜 TJ 大神… 但, async-await
势不可挡, 该用还是得用 0.0, 打算把 co
全部替换为 async
去了. 不过 co
这个库的思想和实现还是可以好好看一看滴.