可以看到,上面我是直接利用了一个 递归 来实现的遍历,然后看下 co 内部是如何实现的,核心代码如下,总的来说,它不能进行处理基础数据,否则会报错,大概的原理和我的也差不多 😅😅
function co(gen) {
var ctx = this;
var args = slice.call(arguments, 1);
// we wrap everything in a promise to avoid promise chaining,
// which leads to memory leak errors.
// see https://github.com/tj/co/issues/180
return new Promise(function(resolve, reject) {
if (typeof gen === "function") gen = gen.apply(ctx, args);
if (!gen || typeof gen.next !== "function") return resolve(gen);
onFulfilled();
/**
* @param {Mixed} res
* @return {Promise}
* @api private
*/
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
return null;
}
/**
* @param {Error} err
* @return {Promise}
* @api private
*/
function onRejected(err) {
var ret;
try {
ret = gen.throw(err);
} catch (e) {
return reject(e);
}
next(ret);
}
/**
* Get the next value in the generator,
* return a promise.
*
* @param {Object} ret
* @return {Promise}
* @api private
*/
function next(ret) {
if (ret.done) return resolve(ret.value);
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
return onRejected(
new TypeError(
"You may only yield a function, promise, generator, array, or object, " +
'but the following object was passed: "' +
String(ret.value) +
'"'
)
);
}
});
}
function toPromise(obj) {
if (!obj) return obj;
if (isPromise(obj)) return obj;
if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
if ('function' == typeof obj) return thunkToPromise.call(this, obj);
if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
if (isObject(obj)) return objectToPromise.call(this, obj);
return obj;
}
自己实现
先来了解下如何实现如下代码:
有没有很熟悉?没错,如果你了解 co 这个库的话,你就知道,
wrapAsync
就相当于 co.wrap一开始拿到这个题,自己也比较懵,因为自己很少使用 Generator,全都直接上手 async/await
大家都知道,
Generator
函数如果碰到yield
会暂停后面代码的执行,要调用next
方法才能向下执行,每次调用next
方法的时候,会返回一个对象,其中value
表示当前 yield 的返回值,done
,表示是否遍历完,如果是,则返回true
,否则返回false
。所以总的代码思路就是去循环判断这个done
是否为true
,然后对后面yield
的返回值做操作。这里就直接讲 如何实现一个类似 co 函数,因为 co.wrap 只不过是 co 的一个简单封装,这里将该函数取名为
rco
,以示区别。先来看下
rco
的基本使用:分析
实现
rco
上述代码说明
done = true
,表示已经遍历完value2Promise
上面说到了,我们会把 yield 后面的值全部转化为 promise,具体代码如下:
关于 thunk
使用
可以说是让用户自己控制何时 resolve
实现
关于收集对象中的 promise 值
使用
因为对象里的属性值也可能是 promise,所以我们需要去收集这些值,直到所有的 promise 都 resolve了之后又,才是真正 resolve 了该对象
实现
关于 rco.wrap
有了上面的基础,rco.wrap 只是基于上面的简单封装:
对比 co
可以看到,上面我是直接利用了一个 递归 来实现的遍历,然后看下 co 内部是如何实现的,核心代码如下,总的来说,它不能进行处理基础数据,否则会报错,大概的原理和我的也差不多 😅😅
最后
rco 已上传至 github,参见rco
如有不足,欢迎讨论 😊😊