月度归档:2018年07月

自己来写个co

昨天被问到实现co()(tj/co) 这个很经典的函数,花了几分钟写了下。后来回想下发现有个地方处理得不是很好,故在此小小地总结下。

首先说下co(gen)这个函数

简单点说,这个函数能够执行传入的生成器函数gen,最后返回一个Promise,当gen一切都顺利进行的时候这个 Promise 应该被以起返回值 resolved, 而当有任何异常发生的时候,这个Promise应该被相应地 rejected.比如正常情况下:
const res = await co(function*(){a = yield 1b = yield 2return 3})
那么期望的结果则是a === 1,b === 2res === 3.此外,co(gen)还有个特点,就是当yield一个Promise的时候,co应该等待这个Promise被 resolved 的时候再把 resolved 的值传回gen,而当其被 rejected 的时候应该要把 rejected 的异常在这个gen函数中抛出。当然真正的co库还会处理 thunk, 基于数组或对象的并行Promise, 还有嵌套的 generator.

最初的版本

function co(gen) {return new Promise((resolve, reject) => {try {const generator = gen()const execute = (generator, value) => {const x = generator.next(value)if (x.done) {resolve(x.value)return}const nextValue = x.valueif (isPromiseLike(nextValue)) {nextValue.then(v => execute(generator, v),e => {generator.throw(e) // 出错了,在generator内部抛出异常execute(generator) // 处理被catch的情况})} else {execute(generator, nextValue)}}execute(generator)} catch (e) {reject(e)}})}
现在来看,这个版本能够处理基本的 yield 一个普通值流程,也能处理 yield 一个 Promise 的情况,甚至即使在 gen 函数刚开始被调用的时候抛出了异常的场景下也能如期返回一个被 rejected 的 Promise.但是,有两个问题:1.generator.throw()的返回值没有处理2.generator.next()以及generator.throw()抛出的异常没有处理首先,先来看下generator.throw()说明
语法gen.throw(exception参数 exception - 用于抛出的异常。 使用 Error 的实例对调试非常有...
阅读全文