JS Promise异步修改返回对象、async/await返回Promise问题咨询
问题解答
问题1:await调用后仍拿到unfulfilled状态Promise的原因
核心原因是对async/await的生效规则理解有偏差:
await关键字仅在async标记的函数内部、或ES模块顶层才能生效,作用是暂停当前上下文的执行,等待后面的Promise落定后再返回resolve的结果。- 如果你把
await instance.methods.isRegistered(...)这段代码写在普通非async函数里,要么直接报语法错误,要么会因为函数本身没有被标记为async,执行时不会等待异步逻辑完成,直接返回pending(即你说的unfulfilled)状态的Promise。 - 还有一种高频错误:你给内部逻辑加了await,也给函数加了async关键字,但调用这个函数的时候没有加await,直接拿返回值,此时拿到的必然是Promise对象,而非最终resolve的结果。
问题2:函数出栈后内部result对象仍能被修改的原因
这是JS的内存管理、闭包机制和控制台打印逻辑共同导致的:
- 函数执行上下文从调用栈弹出,不代表内部声明的变量会立刻被销毁。JS的垃圾回收规则是:只要堆内存中的值还被任意存活的引用持有,就不会被回收。
- 你代码里的
result是对象类型,实际存储在堆内存中:函数return时把这个对象的引用返回给了外部的接收变量,同时.then的回调函数通过闭包也持有了这个对象的引用,两个引用指向堆中同一个对象。等异步操作完成、回调函数入栈执行时,自然可以修改这个对象的属性值。 - 你看到的控制台打印差异是开发者工具的固有特性:打印引用类型时,折叠状态下显示的是打印瞬间的属性快照预览,点击展开时才会重新读取对象当前的最新属性值,所以展开后能看到异步回调写入的新值。
问题3:正确的函数改写方式
首先要明确JS事件循环的基本规则:异步操作的结果永远不可能同步返回,必须用Promise链式调用、或者async/await的方式接收结果,不要写返回空对象再异步改值的逻辑。
推荐写法(async/await)
首先把函数标记为async,内部直接等待异步调用完成后返回构造好的结果对象:
async function checkRegisteredStatus(addr) { const receipt = await instance.methods.isRegistered(session.id, addr).call(); return { status: receipt.status, registrationType: receipt.registrationType }; }
调用时必须加await(注意await只能在async函数内或ES模块顶层使用):
// 业务逻辑示例 async function initBiz() { const addr = '目标地址参数'; const result = await checkRegisteredStatus(addr); console.log(result); // 此处拿到的就是属性赋值完成的完整结果对象 } initBiz();
链式调用写法(不使用async/await)
如果你不想用async/await,可以直接返回Promise实例,在.then回调里拿结果:
function checkRegisteredStatus(addr) { return instance.methods.isRegistered(session.id, addr).call() .then(receipt => { return { status: receipt.status, registrationType: receipt.registrationType }; }); } // 调用方式 checkRegisteredStatus(addr).then(result => { console.log(result); // 此处拿完整结果 // 所有依赖result的逻辑都要写在这个then回调内部 });
内容的提问来源于stack exchange,提问作者ezio
相关产品推荐
相关产品推荐

