【问题标题】:Are promises guaranteed to be executed?承诺是否保证执行?
【发布时间】:2019-08-04 10:14:51
【问题描述】:

假设我们有一个名为logData 的简单函数来处理HTTP 请求。还假设我们有另一个名为logIntoDatabase 的函数。

async logIntoDatabase(message) { ... }

async logData(request, response) {
    await logIntoDatabase("something happened");
    response("log successful");
}

假设我们不需要确定数据是否已记录到数据库中(我们不需要等待数据库的响应)。所以我们做了一点优化:

async logIntoDatabase(message) { ... }

async logData(request, response) {
    logIntoDatabase("something happened");
    response("log successful");
}

绝对保证logIntoDatabase 会执行吗? (好像我们在等待它完成)

【问题讨论】:

  • 我不明白你在问什么。是的,在第二个示例中,logIntoDatabase 仍将被解雇。它只是不会等待它完成后再触发response
  • 好吧,唯一可以保证的是,如果logData 被调用,logIntoDatabase 将被调用。在logDatalogIntoDatabase 通话的开始之间会出现错误吗?甚至在logIntoDatabase 函数中?是的。
  • @zero298 我问这个是因为在 python asyncio 中并非如此。所以我想知道在这种情况下我是否可以信任 nodejs 事件循环。
  • @MinusFour 假设没有错误(我知道,我知道,这是不可能的,但问题的关键是事件循环)。
  • 您不需要处理异步函数的返回值(无论是常规回调还是通过 Promise API),就像您不需要处理同步函数的返回值一样.这取决于你。

标签: javascript node.js promise es6-promise


【解决方案1】:

promise 是否保证会被执行?

首先,这是一些术语正确性,但承诺不会“执行”。异步函数执行并创建承诺来帮助您监控它们的完成情况。你不是在这里打电话给承诺。您正在调用一个返回承诺的函数。

是否绝对保证 logIntoDatabase 会执行?

是的,如果调用了logData(...),那么logIntoDatabase() 将始终作为您的第一个和第二个代码示例中该函数的第一行执行。

你的方法是这样的:

async logData(request, response) {
    await logIntoDatabase("something happened");
    response("log successful");
}

本质上等同于这个(假设logIntoDatabase()返回一个promise并且不同步抛出):

logData(request, response) {
    return logIntoDatabase("something happened").then(() => {
        response("log successful");
    });
}

因此,您可以看到在logData() 中执行的第一行是您对logIntoDatabase() 的调用。


async 函数的完全替代是这样的:

logData(request, response) {
    try {
        return Promise.resolve(logIntoDatabase("something happened")).then(() => {
            response("log successful");
        });
    } catch(e) {
        return Promise.reject(e);
    }
}

这涵盖了其他不当行为,例如 logIntoDatabase() 不返回承诺或同步抛出。但是,即使在这个更完整的类比中,您也可以看到 logIntoDatabase() 仍然保证会被调用。


在您的第二个代码示例中:

async logData(request, response) {
    logIntoDatabase("something happened");
    response("log successful");
}

您仍然可以保证logIntoDatabase() 将被调用。但是,这将在三个方面与您使用 await 的版本不同:

  1. 即使logIntoDatabase() 拒绝,也会始终调用response("log successful")

  2. response("log successful") 将在 logIntoDabase() 完成它的异步操作之前被调用。

  3. logData() 返回的承诺与logIntoDatabase() 是解析还是拒绝没有任何关系。如果logIntoDatabase()resolve("log successful") 都没有同步抛出,那么promise 将被解析为undefined 解析值。如果其中任何一个确实同步抛出,则从logData() 返回的承诺将拒绝,并将异常作为拒绝的原因。

所以,您的第二个示例与此类似:

logData(request, response) {
    try {
        logIntoDatabase("something happened");
        response("log successful");
        return Promise.resolve();
    } catch(e) {
        return Promise.reject(e);
    }
}

而且,您可以看到logIntoDatabase() 仍然保证始终被调用。

【讨论】:

  • 感谢您的详细解答!我暂时将其标记为已接受的答案。 :)
【解决方案2】:

是的,只要调用它的函数 (logData) 也被执行,logIntoDatabase 肯定会执行。

请注意,它不一定会按照您的预期执行:它可能会抛出错误或需要很长时间才能完全执行,尽管这是与函数内容相关的问题,而不是如果您要调用它synchronouslyasynchronously

【讨论】:

    【解决方案3】:

    promise 或异步中的脚本将始终执行,除非 您的应用程序/服务器强制停止或崩溃。

    您可以阅读这篇关于异步工作原理的文章。脚本仍在堆栈中,但未阻塞其他进程。

    https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff

    【讨论】:

      【解决方案4】:

      是的!

      JavaScript 中的 Promise 就像现实生活中的 Promise 一样,一旦做出,就一定会遵守。

      希望对你有帮助

      【讨论】:

      • 嗯,promise 不是“调用”的。它们是一种通知和监控机制。调用异步函数。这些函数可能会返回一个用于监控其完成的承诺。
      • 就像现实一样,一个承诺可以被打破(拒绝)。也无法保证何时会兑现承诺。
      • 这只是个笑话。
      猜你喜欢
      • 2016-06-29
      • 2016-06-01
      • 2019-07-14
      • 1970-01-01
      • 1970-01-01
      • 2020-07-01
      • 1970-01-01
      • 2014-07-22
      • 2016-01-10
      相关资源
      最近更新 更多