摘自 blog.csdn.net/weixin_33826897/arti...
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000))
function * testG() {
// await被編譯成了
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
function asyncToGenerator(generatorFunc) {
// 返回的是一個新的函式
return function() {
// 先呼叫generator函式 生成迭代器
// 對應 var gen = testG()
const gen = generatorFunc.apply(this, arguments)
// 返回一個promise 因為外部是用.then的方式 或者await的方式去使用這個函式的返回值的
// var test = asyncToGenerator(testG)
// test().then(res => console.log(res))
return new Promise((resolve, reject) => {
// 內部定義一個step函式 用來一步一步的跨過yield的阻礙
// key有next和throw兩種取值,分別對應了gen的next和throw方法
// arg引數則是用來把promise resolve出來的值交給下一個yield
function step(key, arg) {
let generatorResult
// 這個方法需要包裹在try catch中
// 如果報錯了 就把promise給reject掉 外部通過.catch可以獲取到錯誤
try {
generatorResult = gen[key](arg)
} catch (error) {
return reject(error)
}
// gen.next() 得到的結果是一個 { value, done } 的結構
const { value, done } = generatorResult
if (done) {
// 如果已經完成了 就直接resolve這個promise
// 這個done是在最後一次呼叫next後才會為true
// 以本文的例子來說 此時的結果是 { done: true, value: 'success' }
// 這個value也就是generator函式最後的返回值
return resolve(value)
} else {
// 除了最後結束的時候外,每次呼叫gen.next()
// 其實是返回 { value: Promise, done: false } 的結構,
// 這裡要注意的是Promise.resolve可以接受一個promise為引數
// 並且這個promise引數被resolve的時候,這個then才會被呼叫
return Promise.resolve(
// 這個value對應的是yield後面的promise
value
).then(
// value這個promise被resove的時候,就會執行next
// 並且只要done不是true的時候 就會遞迴的往下解開promise
// 對應
// gen.next().value.then(value => {
// gen.next(value).value.then(value2 => {
// gen.next()
//
//
// 此時done為true了 整個promise被resolve了
//
// 最外部的test().then(res => console.log(res))的then就開始執行了
// })
// })
function onResolve(val) {
step("next", val)
},
// 如果promise被reject了 就再次進入step函式
// 不同的是,這次的try catch中呼叫的是gen.throw(err)
// 那麼自然就被catch到 然後把promise給reject掉啦
function onReject(err) {
step("throw", err)
},)
}
}
step("next")
})
}}
var test = asyncToGenerator(testG)
test().then((res) => {
console.log(res);
})
本作品採用《CC 協議》,轉載必須註明作者和本文連結