【问题标题】:clarification about promises in javascript关于 javascript 中的承诺的澄清
【发布时间】:2021-09-29 11:06:06
【问题描述】:

我对有关承诺的某些部分感到困惑,我已经阅读了多篇文章,也看过多个视频,我想问一些事情:

据我目前了解,当一个承诺被创建时,它开始运行。

如果从promise返回的值没有在代码中使用,我是否需要等待promise?

一个场景是:假设我正在我的系统中处理一个任务,并且我想将信息记录到 mongodb,当我调用插入函数时,我得到了一个承诺。处决者,但我不在乎它的结果

如果我不等待并且出现错误,我将无法处理它。

上述问题的后续问题:

从我每次await 读到的内容来看,它实际上会阻止异步函数的执行,但如果它阻止了函数的执行,它如何不阻止事件循环的其余部分?

【问题讨论】:

标签: javascript node.js promise


【解决方案1】:

基本概念

事件循环的全部意义在于有许多互不影响的微任务(因此默认情况下没有影响)。

首先链接微任务;有回调,然后是 Promises (then/catch),然后是 async/await API。最后两个可以被认为只是回调概念之上的语法糖。没有添加“功能”,而是使用不同的语法以更简单、更优雅的方式实现相同的东西(Pyhilosophicaly)。

事件循环在每个循环中执行所有排队的微任务并重复。除非您有阻塞代码(并且await 不被视为阻塞),否则您的事件循环永远不会停止,因此其他任务不会受到影响。

您正试图从其他语言中的实际阻塞代码的角度来理解await

恕我直言,您首先需要深入了解回调是如何工作的,然后研究 Promises(作为一种使回调不那么混乱的工具),然后是 async/await(作为使 Promises 更漂亮的语法)。但请记住,底层系统是相同的:调用函数的函数得到处理的函数最终会被调用)。

具体问题

当一个promise被创建时开始运行

是的,但不是。承诺不会运行,承诺只是您通过部分代码收到的合同,该部分代码将用于通知您结果。所以 promise 没有运行,是在你请求执行任务后为你创建的意思。

因此,通常如果向您处理了一个承诺,就会有一些“正在运行”的东西。但是Promise 的用法可能不同,可能会有一些“等待”。

promise 与任务的执行无关,因此它无法启动或停止它。

如果我对结果不感兴趣,是否需要等待承诺?

不,您不需要这样做。但请记住,不处理承诺异常已被弃用,并可能导致系统故障。您应该始终处理(或冒泡)异常。

如果存在未处理的 Promise 拒绝,则会失败。在同步代码中,这相当于未捕获的抛出错误。直到现在(-ish)未捕获的承诺拒绝被容忍,但没有一个很好的理由。 Node 正在将它们视为与冒泡到顶部的任何其他错误相同的处理方式。

VLAZ

您只考虑使用async/await 的承诺,但底层Promise api 是.then().catch()。使用此 API,您可以以“即发即弃”的方式使用 Promise:

async function Do() {
  await before();
  asyncDbCall().catch(err => console.error(err))
  await after();
}

在此示例中,您不等待asyncDbCall(),但.catch(err => console.error(err)) 仍将导致错误被记录(在将来的某个时间,甚至可能在Do() 完成之后)。

或者您可以将执行分支到其他异步执行,举个复杂的例子:

async function Do() {
    await before();
    // This will execute AFTER before() & only if before() succeeded
    asyncDbCall()
        .then(async value => {
            // This will execute after `asyncDbCall()` and only if it succeeded
            await something(value);
            // We reach here after `something()` and only if succeeded
        })
        .catch(err => {
            // This will execute if `asyncDbCall()` fails of IF ANYTHING
            // within `async value => {}` fails
            console.error(err);
        })
    // This will execute AFTER before() and only if before() succeeded and
    // asyncDbCall() call (but not Promise) succeeded
    await after();
}

Await 实际上阻塞了异步函数的执行

Await 停止 async 函数(因此还有任何正在等待该函数的函数),但无论如何都不会影响事件循环。

【讨论】:

  • 所以如果一个异步函数等待一个承诺,它不会阻止事件循环继续处理对函数的下一次调用?
  • "请记住,不处理承诺异常已被弃用,并可能导致系统故障。" 我支持这一点。只是一个小小的澄清,如果有未处理的承诺拒绝,就会失败。在同步代码中,这相当于未捕获的抛出错误。直到现在(-ish)未捕获的承诺拒绝被容忍,但没有一个很好的理由。 Node 正在将它们与冒泡到顶部的任何其他错误一样对待。
  • 是否有不应该等待的场景?
  • @VLAZ 你说得很好。我抄袭了它并将其添加到答案中;)
  • @Eitank 默认情况下没有分支执行。多线程是 JS 中的一种选择,异步任务通常仍然在单线程中处理。有关更多解释,请参阅我对 Please point out the misfacts in my learning regarding Asynchronous Javascript 的回答。任何承诺完成都会在处理之前添加到微任务队列中。如果你有一些火而忘记的任务,那么所发生的只是它所在的功能不会等待它完成,而是会正常继续。因此,解决该任务仍会添加一个
【解决方案2】:

据我目前了解,当一个承诺被创建时,它开始运行。

事实并非如此。它的内部状态设置为pending。 Promise 的构造函数将回调作为参数,并依次为其提供resolvereject 回调。

它还允许提供许多操作 当它的状态变为resolvedrejected 时发生。在async/await 之外,您可能知道它们为.then.catch 类的Promise 实例方法。一旦状态改变,它们就会被执行。

如果从promise返回的值没有在代码中使用,我是否需要等待promise?

不,这完全取决于你。

一个场景是:假设我正在我的系统中处理一个任务,并且我想将信息记录到 mongodb,当我调用插入函数时,我得到了一个承诺。处决者,但我不在乎它的结果

如果我不等待并且出现错误,我将无法处理它。

您仍然可以使用.catch 来处理错误,而无需等待Promise 完成

上述问题的后续问题:

从我每次等待时读取的内容来看,它实际上阻止了异步函数的执行,但如果它阻止了函数的执行,它如何不阻止事件循环的其余部分?

Promise 与事件循环无关。

您可以阅读有关 EventLoop 的更多信息here.

【讨论】:

    猜你喜欢
    • 2016-11-09
    • 2015-01-31
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    • 2012-08-22
    • 1970-01-01
    相关资源
    最近更新 更多