async實現解讀
解讀前我們要首先關注幾個問題:
- 如何確保async返回一個promise, 而且狀態必須等里面全部await后面的promise確定完后才確定
- 如何確保所有的async里面直接拋出的異常能被捕獲
- 如何確保await后面的promise為reject的時候,async立即停止執行,而且返回promise為reject
上面的三點是處理async執行流中最關鍵的三點。
2 和 3 如何解決呢? 想一下,生成器在迭代的時候,上面時候會拋出異常呢? 是不是在生成器執行 next函數期間,如果中途遇到異常的話,是不是會外拋出? 所以我們只需要在生成器執行next處捕獲異常就行了
如何在 await 后面的promise為 reject的時候,拋出異常呢?我們可以獲取yield后面的promise對象,如果執行完后為 reject, 那么直接使用 generator的 .throw api,往生成器內部拋異常,如果內部無法捕獲的話,那么它會在對應的next出往外拋,即又和2一樣了,我們同樣可以在next處 來捕獲 await后面的 promise 為reject異常,只是這個異常是我們自己拋的而已。
function spawn(genF) {
//直接返回一個promise 解決1
return new Promise(function(resolve, reject) {
var gen = genF();
function step(nextF) {
// 這里捕獲兩種異常,一種為 generator內部可能直接拋的異常
// 一種為我們跑到await后面的promise為reject時候,我們主動拋的異常
try {
var next = nextF();
} catch(e) {
return reject(e);
}
//生成器執行完成后 才resovle 解決1
if(next.done) {
return resolve(next.value);
}
// 為什么使用resolve呢? 兼容的原因,如果next.value可以為promise,也可以為
//其他普通值
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}