使用generators与Promise模拟async/await时输出pending Promise如何解决
基于Generator与Promise手动实现async/await核心逻辑
背景
学习生成器相关知识时,希望不直接使用async/await语法,通过生成器结合Promise模拟异步请求逻辑,手动实现async/await的核心原理。
首次尝试代码及问题
首次编写的代码运行后控制台始终打印pending状态的Promise,代码如下:
function* awaitReq() { const val1 = new Promise((resolve, reject) => { setTimeout(() => resolve(5)) }).then((val) => val ) .catch((err) => "Error"); yield val1; // second call yield val1 * 2; } const generator = awaitReq(); const { value, done } = generator.next(); // check if val is a number or error if(isNaN(value)) { console.log(value) return value; } // otherwise, return the setTimeOut response times 2 console.log(generator.next().value)
问题分析
- 第一次yield返回的是Promise实例本身,代码没有等待Promise状态变更就直接做
isNaN判断,此时value为pending状态的Promise,判断永远为真,无法进入后续逻辑 - val1本身是Promise对象,不能直接参与
val1 * 2这类算术运算,即使拿到异步结果也会得到NaN - 缺少自动推进生成器执行的逻辑,手动调用
next的时机早于异步任务完成时间,无法拿到预期结果
可行实现方案
调整后可正常运行的实现代码如下:
function getNumber() { return new Promise((resolve, reject) => { resolve(10); }).then((val) => { return new Promise((resolve, reject) => { resolve(val * 2) //reject("Error"); }).then((val2) => val2); }).catch((err) => { return err; }) } // 接收生成器函数作为参数 function run(generatorFn) { const iterator = generatorFn(); // 创建迭代器实例 const handleNext = (value) => { const next = iterator.next(value); if(next.done) { return next.value; } else { return Promise.resolve(next.value) .then((val) => handleNext(val)) .catch((err) => handleNext(err)); } } handleNext(); } run(function* () { try { const result = yield getNumber(); console.log(result); } catch (ex) { console.log('Error: ' + ex); } })
核心逻辑说明
run函数是async/await语法糖的核心实现:接收生成器函数作为入参,生成对应的迭代器实例handleNext函数负责自动推进迭代器执行:每次拿到yield返回的值后,统一封装为Promise,等待Promise状态敲定后,将结果作为参数传入iterator.next,注入到生成器内部作为yield表达式的返回值,再递归推进下一次迭代,直到迭代器完成- 原生支持错误处理:如果yield返回的Promise触发reject,错误会被传入迭代器,可被生成器内部的
try/catch捕获,表现和原生async/await一致
内容的提问来源于stack exchange,提问作者myTest532 myTest532
相关产品推荐
相关产品推荐

