async函数的polyfill

async函数本身是generator的语法糖,在不支持async函数的场景下可以使用genrator函数来实现async函数的效果。
假设有以下代码:
function wait1() { return new Promise((r) => { setTimeout(() => { r('result1'); }, 1000); }); } function wait2() { return new Promise((r) => { setTimeout(() => { r('result2'); }, 1000); }); }
我们需要先执行wait1并等待返回结果,之后再执行wait2等待返回结果,如果使用async函数,那么这将非常简单:
async fn(){ const res1 = await wait1(); const res2 = await wait2() }
当时在不支持异步函数的环境下,需要用generator函数来实现相似的效果。
首先yield关键子可以“暂停”函数的执行,并取得其后的返回值,这和await很像,但是区别在于await能够等到其后函数异步完成后继续执行async函数,而yield需要我们自己手动判断什么时候需要继续执行函数,由于wait函数返回是Promise,因此我们需要一个额外的函数辅助,当wait的promise进入resolve状态时,就是generaotr函数继续执行的时刻。
完整代码如下:
function wait1() { return new Promise((r) => { setTimeout(() => { r('result1'); }, 1000); }); } function wait2() { return new Promise((r) => { setTimeout(() => { r('result2'); }, 1000); }); } // 模拟async函数 function* asyncFn() { const result1 = yield wait1(); console.log('wait1执行完了', result1); const result2 = yield wait2(); console.log('wait2执行完了', result2); return [result1, result2]; } // 由于generator函数不能自动执行,因此需要一个辅助函数管理执行状态 function runFn(generator) { const g = generator(); function handleNext(iterator) { if (iterator.done) { return Promise.resolve(iterator.value); } return Promise.resolve(iterator.value) .then((e) => handleNext(g.next(e))) .catch((e) => handleNext(g.throw(e))); } try { return handleNext(g.next()); } catch (err) { throw err; } } runFn(asyncFn) .then((res) => { console.log(res); }) .catch((err) => { console.error(err); }); // wait1执行完了 result1 // wait2执行完了 result2 // ['result1', 'result2']