当 Promise 永远不会解决时会发生啥? [复制]

Posted

技术标签:

【中文标题】当 Promise 永远不会解决时会发生啥? [复制]【英文标题】:what happens when a Promise never resolves? [duplicate]当 Promise 永远不会解决时会发生什么? [复制] 【发布时间】:2018-04-08 13:52:27 【问题描述】:

我有这个使用 es6 async await 语法的非常令人困惑的 sn-p 代码。我期望发生的是该进程永远挂在await 行上,因为从未调用过resolve 函数。然而,实际发生的是输出“start”,然后进程退出,没有更多输出。

const simple = async () => 
  console.log('start')
  await new Promise(resolve => )
  console.log('done.')

simple()

但是,下面的这段代码将打印“开始”,等待 1 秒,然后打印“完成”。

const simple = async () => 
  console.log('start')
  await new Promise(resolve => setTimeout(resolve, 1000))
  console.log('done.')

simple()

我对这意味着什么的最接近的猜测(没有任何证据)是,当 node 正在等待一个 promise 时,它​​会跟踪代码中发生的活动事情,当没有其他事情发生时,它会简单地退出。有人可以解释为什么代码在这里退出吗?

运行node v8.7.0

【问题讨论】:

我发现还有一件事值得一提,以便更容易理解这里发生的事情。由于它是一个async/await 函数,因此它不同于常规函数,后者总是运行到完成。如果您重写simple 以不使用async/await,则必须将await 语句之后的代码放在.then() 回调中。由于您不调用resolve(),因此该代码将永远不会执行,因此控制台不会打印“完成”。然而,Promise 的主体是立即执行的,因为它是空的,所以程序没有任何东西可以执行! 好点子!在没有async/await 语法的情况下考虑这一点,代码停止执行的原因就更明显了 一个很好的解释可以在这里找到:***.com/a/36735167/890357 【参考方案1】:

是的,你对正在发生的事情有误解。

正如你所说,由于你提到的原因,在await 调用之后代码将永远不会继续,但这并不重要。

当您调用simple() 时,该方法本身会返回一个promise - 而您并不是在等待该promise。调用simple() 后您的执行将继续,并立即结束您的程序。

更详细地说,当没有更多回调要处理时,nodejs 将退出。当您返回您违反的承诺时,您还没有在 nodejs 队列中创建回调(就像您执行 http 请求一样)。如果你采取措施让 nodejs 保持活力,你会看到 done 永远不会被执行。

const simple = async () => 
  console.log('start')
  await new Promise(resolve => )
  console.log('done.')

var promise = simple();

// keep the application alive forever to see what happens
function wait () 
    setTimeout(wait, 1000);
;
wait();

如果有一个挂起的回调(由setTimeout 创建,或者来自加载资源,或者等待 http 响应),那么 nodejs 将退出。但是,在您的第一个示例中,您没有创建任何回调 - 您只是返回一个破碎的承诺。 Nodejs 没有看到任何“待处理”的东西,所以它退出了。

基本上在您的simple 调用结束时,您没有更多代码可以执行,也没有任何待处理(没有等待回调),因此nodejs 安全地知道没有其他事情要做。

【讨论】:

你说得对,done 永远不会被执行,但是这段代码可以等待在那里做某事的承诺,如果你用await new Promise(resolve => setTimeout(resolve, 1000)) 替换await 行,代码将输出“完成”之后,simple() 不需要任何处理程序。我已经更新了我的问题以显示这个 @andykai 是的!确切地。这正是我所说的。 setTimeout 方法创建一个 callback nodejs 正在寻找的。如果有任何挂起的回调,nodejs 将不会退出。你的第一个例子没有创建任何挂起的回调,它只是返回一个promise。【参考方案2】:

我最接近的猜测......它会跟踪代码中发生的活动,当没有其他事情发生时,它就会退出。

这基本上是正确的。 Node 会保留诸如计时器和网络请求之类的引用计数。当您发出网络或其他异步请求时,设置计时器等。节点添加到此引用计数。当时间/请求解决节点从计数中减去时。

这个计数是 Node 在事件循环结束时决定是否退出的方式。当你到达事件循环的末尾时,节点会查看这个计数,如果它为零则退出。简单地做出承诺,不会增加引用计数,因为它不是异步请求。

[Node 核心开发人员] Bert Belder 对此进行了很好的讨论,这很有帮助:https://www.youtube.com/watch?v=PNa9OMajw9w

【讨论】:

谢谢你的谈话很有见地!关于 ref++ref-- 跟踪每件事和承诺不添加计数的观点非常清楚地描绘了该程序退出的原因 为什么第三行done 不能保持进程存活?还有更多的 javascript 需要执行!我理解不向队列添加回调的空承诺,但为什么脚本的其余部分被忽略了?

以上是关于当 Promise 永远不会解决时会发生啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序在 Cordova 中退出时会发生啥事件?

当 GIT 用完您的修订版的哈希值时会发生啥?

mmap local v/s nfs file:当底层文件在磁盘上被替换时会发生啥?

动作脚本 3. 在 gotoAndStop() 之后动画永远循环,并且在动画过程中当角色发生碰撞时会有延迟

当活动崩溃时会发生啥?

当多个线程想要访问 ReentrantReadWriteLock 时会发生啥?