为什么同一段JavaScript异步代码在Node.js中输出后立即退出,Deno中延迟退出
两段运行环境的行为差异拆解
先理清楚这段代码的核心bug
- 写
sleep函数的时候踩了JS的经典参数求值坑:执行new Promise的同步执行器逻辑时,setTimeout(resolve(time), time)这行的逻辑是先把所有参数算完再传给setTimeout。也就是说resolve(time)根本不是等定时器到点才执行,是立刻同步跑起来的,直接把对应的Promise标记为成功状态,返回值就是传进去的时间数字。 - 等参数算完,
setTimeout拿到的第一个参数是resolve(time)执行后的返回值——因为resolve函数本身没有返回内容,所以拿到的是undefined,相当于写了setTimeout(undefined, time)。这个调用根本不会注册任何要执行的回调,只是给事件循环提了一句“我登记了一个等待X时长的定时器”。 - 所有逻辑根本没有真实等待:两个异步函数里的每一次
sleep调用都会立刻跑完,所有console.log语句几毫秒就全部执行完,输出的就是示例里的三行内容。
Node.js环境下打印完就直接退出的原因
- Node判断能不能结束进程的逻辑非常干脆:等事件循环扫完一圈,发现没有任何带有效回调的待处理异步任务(比如能触发的定时器、没跑完的I/O、没断开的网络连接),就直接终止进程,多一秒都不等。
- 对于这种传了
undefined当回调的无效setTimeout调用,Node直接判定为不合法的任务,根本不会把它放进待处理队列。等所有同步代码、微任务跑完,Node扫一圈队列发现是空的,自然直接退出,不会额外等待。
Deno环境下要等一段时间才退出的原因
- Deno判断能不能结束进程的逻辑和Node存在差异:只要你调用过
setTimeout,不管传的回调是不是有效函数,它都会把这个定时器的等待时长算成必须等完的待办任务,等所有登记的定时器时间全部走完,才会觉得事件循环空了,可以退出了。 - 这段代码里一共调了四次
setTimeout,分别登记了1秒、2秒、2秒、3秒的等待时长,虽然这些定时器根本没有要执行的回调,但Deno还是会等这些时间全部耗完才结束进程。因为所有打印几毫秒就打完了,自然就会出现“打印完内容还要等几秒才退出”的现象。
内容的提问来源于stack exchange,提问作者ADITYA KUMAR
相关产品推荐
相关产品推荐

