async函数代码未执行问题排查及Node.js同步等待实现咨询
问题分析与解决
为什么console.log('end')不执行?
这问题我之前踩过坑,核心原因出在你写的setTimeoutSync函数里——你的Promise从来没有被resolve!
你看,setTimeoutSync返回了一个Promise,但内部只调用了setTimeout(fn, milli),却完全没触发resolve()方法。await的工作逻辑是:必须等到Promise的状态变为resolved(或者rejected),才会继续执行后面的代码。现在这个Promise一直处于pending挂起状态,run函数里的await就会无限等待,后面的console.log('end')自然永远没机会运行。
修正后的setTimeoutSync应该是这样:
function setTimeoutSync(fn, milli) { return new Promise((resolve) => { setTimeout(() => { fn(); // 先执行传入的回调 resolve(); // 关键:调用resolve让Promise状态变为resolved }, milli); }); }
这样当setTimeout的回调执行完后,Promise就会被标记为完成,await就会放行,后面的console.log('end')就能正常打印了。
Node.js中实现同步等待的合适方法
推荐方案:async/await + Promise(非阻塞事件循环)
Node.js的设计是异步优先,所以最好用非阻塞的方式实现“同步等待”,最优雅的就是结合async/await和Promise:
- 自己封装sleep函数(和上面修正后的逻辑一致):
function sleep(milli) { return new Promise(resolve => setTimeout(resolve, milli)); } async function run() { console.log('start'); await sleep(3000); // 等待3秒,不阻塞事件循环 console.log('end'); } run();
- 用Node.js内置的
util.promisify转换原生setTimeout:
const util = require('util'); const sleep = util.promisify(setTimeout); async function run() { console.log('start'); await sleep(3000); console.log('end'); } run();
不推荐的阻塞式等待
如果非要用传统的“阻塞式”同步等待(强烈不建议,因为会卡住Node.js的事件循环,导致服务无法处理其他请求),可以用死循环卡时间,但这种写法在实际项目里绝对要避免:
function blockSleep(milli) { const start = Date.now(); while (Date.now() - start < milli) { // 啥也不干,空转阻塞 } } function run() { console.log('start'); blockSleep(3000); console.log('end'); } run();
内容的提问来源于stack exchange,提问作者HenryTK
相关产品推荐
相关产品推荐

