很久以前用koajs 1的时候也看过co库的核心源码,后来不用了,前段时间又涉及到了相关的问题,特地重新学习一下, koajs 1 中如何实现的async await的效果。
首先,2个基本知识:
- Promise.resolve flattens nested layers of promise-like objects (e.g. a promise that resolves to a promise that resolves to something) into a single layer.
- gen.next(value) The value to send to the generator. The value will be assigned as a result of a yield expression. i.e in [variable] = yield [expression], the value passed to the .next function will be assigned to [variable]
既然是程序员,还是直接分析代码吧。
function doTask1() {
return new Promise((resolve) =>
setTimeout(
() => resolve(1111),
1111
)
)
}
function doTask2() {
return new Promise((resolve) =>
setTimeout(
() => resolve(2222),
1111
)
)
}
function runner(gen) {
const g = gen();
function run(arg) {
console.log('arg', arg);
let result = g.next(arg); // 2
if (result.done) {
console.log('done', result);
// return result.value; done的时候
} else {
console.log('result.value', result.value);
return Promise.resolve(result.value).then(run); //4
}
}
run(); // 1
}
runner(function* () {
const result1 = yield doTask1(); //3
console.log(result1);
const result2 = yield doTask2(); //5
console.log(result2);
});
程序真正的起始点是1处,2处调用next方法就会执行到3处的yield,此时2处的result就是一个这样的对象:
{ value: Promise { <pending> }, done: false }
其value是一个处于pending状态的promise,这个promise将来会发射出1111。之后程序执行到4处,根据知识点1,4处的then接收到的值会是1111,之后会进行这样的调用:run(1111)。
程序又执行到2处,根据知识点2,next方法传值1111给3处的result1。。。,这次的next会执行到5处的yield,这个yield会返回这样的一个对象:
{ value: Promise { <pending> }, done: false }
这个对象又会赋值给2处的result,之后又执行到4处,后面的同理不说了
注:
在写此篇博客的时候,身边有一位远在千里之外的小可爱陪伴,让我想起一首词,放在这里送给她吧:
少年游
张耒
含羞倚醉不成歌,纤手掩香罗。
偎花映烛,偷传深意,酒思入横波。
看朱成碧心迷乱,翻脉脉、敛双蛾。
相见时稀隔别多,又春尽、奈愁何。
参考文献:
https://hackernoon.com/async-await-generators-promises-51f1a6ceede2
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next