【问题标题】:Might a promise be garbage collected too early without a .then() in JavaScript如果没有 JavaScript 中的 .then(),承诺可能会过早地被垃圾收集
【发布时间】:2019-06-16 16:34:40
【问题描述】:

所以基本上我想异步执行 2 个同步承诺。像这样:

(function foo() {
  var newValues = ...;
  this.getMessages().then((msgs: Array<any>) => {
    this.saveMessages(msgs.concat(newValues));
  });
})()

现在因为我不想等待saveMessages 完成执行,所以我没有在最后添加.then()。因为我不在乎结果。我只是想执行异步函数,所以在某些时候我们让消息离线。

但我担心承诺可能会被垃圾收集,因为按照标准(据我所知)你总是需要 .then 来表示承诺。

所以我的问题是我是否需要添加一个空的.then 以确保它不会太早地被垃圾收集并且函数不会正确执行。像这样:this.saveMessages(msgs.concat(newValues)).then();?

在浏览器和NodeJS中是一样的吗?

【问题讨论】:

  • ...promise 可能会被垃圾收集... - 你这是什么意思?另外,您面临的问题是什么?
  • 为了解决promise,不需要加.then()
  • 我认为您的意思是 asynchronously 而不是 synchronous context
  • 还要注意在 JS 中如何使用“上下文”这个词,因为它具有非常特定的含义,使用时可能会引起混淆……完全脱离上下文;)……@987654321 @

标签: javascript node.js promise es6-promise


【解决方案1】:

但我担心承诺可能会被垃圾收集,因为 标准(据我所知)你总是需要一个.then() 来承诺。

没有。不存在任何这样的标准——据我所知——它规定如果没有附加 .then() 对象,GC 将释放分配给 Promise 对象的内存。

无论是否附加了.then()(或a .catch()),Promise 都会被执行。

所以我的问题是我是否需要添加一个空的.then() 来确保 它不是垃圾收集得太早并且函数不会执行 正确。

不,您不需要空的.then()

在浏览器和NodeJS中是一样的吗?

可以,只要您在两个运行时使用相同的 Promise 实现即可。


所以,你完全可以接受:

function foo() {
  var newValues = ...;
  this.getMessages().then((msgs: Array<any>) => {
    this.saveMessages(msgs.concat(newValues));
  });
}

但是,您应该考虑将.catch() 附加到它以处理任何错误。如果你不这样做,你将拥有UnhandledPromiseRejectionWarning。在 Node 的未来版本中,它可能会使您的整个应用程序崩溃。阅读它here

编辑

即使父进程没有任何东西要处理或执行,程序也会等到 100 个 Promise 中的每一个都已解决。试试这个:

const n = 100;

const sleep = (id, seconds) =>
    new Promise(resolve => {
        setTimeout(() => {
            console.log(`promise with id ${id} is resolving`);
            resolve();
        }, seconds * 1000);
    });

for (let i = 0; i < n; i++) {
    sleep(i, 1 * i);
}

console.log("Last line of parent");

【讨论】:

  • 好的,所以垃圾收集似乎不是问题(从这个问题的所有答案来看)。但是“在 Promise 解决之前完成 [...] 的执行上下文”(参见 cantuke 的回答)呢:stackoverflow.com/a/54322111/3955332
  • 那个答案是错误的。我将添加一个 sn-p,它可以帮助您确定在每个 promise 完成之前程序不会结束。
  • @cantuke 完全正确——即使 Last line of parent 首先执行,它也会打印所有正在解析的 promise 日志。但是根据您的回答,它应该只打印 Last line of parent 并退出——因为没有人在等待这些承诺被执行
  • 有趣。感谢您的额外剪裁。让我们问问“对方”这是如何影响执行上下文的。
  • @AnandUndavia 感谢您纠正我。我什至已经开始在 Node.js 中设置我的示例,所以如果你没有纠正我,我会一直对此一无所知。 (掌心)
【解决方案2】:

不,Promise 对您如何处理它的完成一无所知,直到它到达那里。

您无需担心抢先式垃圾收集,Javascript 比这更聪明,但您必须担心全局执行上下文完成,例如在 Promise 解决之前关闭连接的程序,这然后将取消承诺并执行垃圾收集。

由于您是异步运行它,如果您想保证程序等待该 Promise 的完成而不使所有内容同步,您始终可以在作用域变量上保持 Promise 的完成状态或使用事件发射器...

var imDone = false;

function foo() {
  var newValues = ...;
  this.getMessages().then((msgs: Array<any>) => {
    this.saveMessages(msgs.concat(newValues))
         .catch(err=> { console.log(err); imDone = true; })
         .then(()=> imDone = true);                           
  }).catch(err=> console.log(err));
}

....

if (imDone) {
  // finish execution, res.send() or res.end() in Node
} 

【讨论】:

  • 这就是我一直在寻找的:执行上下文可能是问题而不是垃圾收集。
  • 能否请您提供一些资源或文章,这些资源或文章更深入地介绍了如何在同步函数中使用 Promise 处理执行上下文?
  • 你在睡觉前抓住了我,所以我明天必须给你一个更彻底的解释,但总的来说,你的问题的“如何”非常简单,在概念上和应用程序中,只需将执行上下文视为您的计算机(隐喻),现在您的程序 按下电源按钮 与使用正确的关闭程序。我们想在它断电之前创建一个提醒,上面写着“嘿,你想为你保存任何文档吗?”。您需要在程序中创建适当的流控制,这是您进行大量异步编程后的第二天性。
  • 在 Promise 解决之前,它的父函数调用 return 或您的程序完全关闭其线程,这将取消 Promise 并执行垃圾回收。 错误。直到promise 的范围被解决或被拒绝,程序才会退出。
  • 其中一些主题的“为什么”很快就会变得相当学术和抽象,其中大部分不会立即适用于这个问题,但我想如果你'对学习 JS 很认真,值得深入挖掘...Promise: Completion Event...Promises: Cain Flow。这些是凯尔·辛普森 (Kyle Simpson) 的在线书籍的部分内容,介绍了 JS 的具体细节
【解决方案3】:

您可以使用此代码并返回您的第一个承诺,第二个承诺是运行同步。

function foo() {
  var newValues = ...;
  return this.getMessages().then((msgs: Array<any>) => {
    this.saveMessages(msgs.concat(newValues));
  });
}

【讨论】:

  • 您能否说明这与垃圾收集或执行上下文完成有何关系?
【解决方案4】:

您没有以正确的方式执行代码。应以正​​确的方式处理承诺。垃圾收集器释放空间没有问题。您的代码可以以这种方式编写,这将增加可读性并使代码更易于理解。

// This is pseudo synchronous execution of the code
function foo() {
  var newValues = 'testing';
  return this.getMessages()
  .then((msgs: Array<any>) => {
    // here return is important
    return this.saveMessages(msgs.concat(newValues));
  });
}

您可以使用 async/await 功能降低复杂性:

aync function foo() {
    try {
        var newValues = 'testing';
        const msgs = await this.getMessages()
        await this.saveMessages(msgs.concat(newValues))
    } catch (ex) {
        // handle your error here
    }
}

【讨论】:

  • 能否详细说明这里的回报很重要
  • 对于代码的伪同步执行,我们必须确保实现的.then() 应该在this.saveMessages((我假设this.saveMessages 将返回一个Promise)函数之后运行。如果我们不使用 return 那么this.sageMessages 将被抛出堆栈。所以代码的执行不会是同步的
  • 啊,我明白了。我认为这个问题有点混乱,因为 OP 在问题synchronous contextI don't want to wait for saveMessages to finish 中有一些矛盾的语言。
  • 据我所知,他们希望foo() 执行异步,但需要注意它必须在某个时候完成。我确实认为在执行结束时等待foo() 本身,你拥有它的方式,是处理它的最优雅的方式。
  • 你好。所以在我的问题中,场景没有 async / await -> 我知道我通过使用 async / await 来保存,但想知道如果我不想在同步函数中等待异步函数会发生什么
猜你喜欢
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 1970-01-01
  • 2013-10-18
  • 2011-10-12
相关资源
最近更新 更多