然后无法理解Promise并捕获行为

时间:2018-11-19 08:16:56

标签: javascript promise

以下代码的实际输出(在Firefox控制台中显示)为     -错误1     -错误2     -继续1     -继续3。

Promise
  .resolve()
  .then(() => Promise.reject('error1'))
  .catch(console.log)
  .then(() => console.log('continue1'))

Promise
  .resolve()
  .then(() => Promise.reject('error2'))
  .then(() => console.log('continue2'), console.log)
  .then(() => console.log('continue3'))

据我对诺言的理解,应该是-错误1-继续1-错误2-继续3。

需要帮助来了解实际输出

3 个答案:

答案 0 :(得分:4)

首先,试图理解两个完全独立的promise链之间可能存在的排序问题是毫无意义的。进行编程时,应将它们的顺序视为不确定的(实际上,一旦在任何真实的promise链实现通常包含的promise链中有真正的异步操作,该顺序就会变得不确定)。如果两个链之间的顺序对您很重要,那么您需要添加一些特定的代码来协调两个独立的Promise链的动作。

因此,您在代码段中观察到的顺序是:

error1
error2
continue1
continue3

由于在任何.then().catch()处理程序中都没有异步操作,因此它将简单地在两个Promise链之间交替(这是运行代码段时的工作) 。基本上是这样执行的:

  1. 首先执行Promise.resolve(),这会在事件队列中添加一个事件,以运行其.then()处理程序。
  2. 执行第二个Promise.resolve(),这会向事件队列添加一个事件,以运行其.then()处理程序。
  3. 您的JS序列已完成,因此控制权返回到事件队列。首先调用.then()处理程序,然后将另一个事件插入事件队列以运行.catch()处理程序并将控制权返回到事件循环。
  4. 第二个.then()处理程序位于事件队列的顶部并开始运行
  5. 依此类推...

请记住,根据promise规范,每个连续的.then().catch()处理程序都必须异步运行(在事件队列的下一轮)。诺言链没有尽其所能。它执行下一步,将其后的步骤放入队列,然后将控制权返回给事件循环,该事件循环将下一个事件弹出队列。这将导致控件在不同的promise链之间轮换,这些promise链不需要等待其他事情完成。

但是,我重复一遍,您不应该依赖于此执行顺序级别,并且在涉及其他异步操作的更复杂的实际情况下,您不能尝试预测顺序。您应该假设这两个单独的承诺链以不确定的顺序运行,超出了同步部分(每个Promise.resolve())。然后,如果您的代码有任何特定的排序问题,则必须添加代码以使用Promise.all()来实际同步和控制执行顺序,或将这些链链接在一起成为一个分支链或一个序列链,或者取决于代码的需求。

答案 1 :(得分:1)

解决/拒绝的承诺将微任务放入相应的队列中。该任务涉及调用任何then / catch回调函数。该队列中的消息将按顺序处理。

所以在您的示例中,顺序为:

  • 首先执行Promise.resolve()。微任务队列现在有1个条目:

    • 队列= [已解决承诺1]
  • 正常执行流程继续到第二个Promise.resolve()

  • 第二个Promise.resolve()被执行。现在,微任务队列有2个条目:

    • 队列= [已解决承诺1,已解决承诺2]
  • 正常执行流程结束-调用堆栈为空。

  • 提取并处理队列中的第一项。 then回调() => Promise.reject('error1')被执行。这会创建一个新的,被拒绝的承诺,因此将拒绝添加到队列中

    • 队列= [解决了承诺2,答应。然后拒绝了#1]
  • 提取并处理队列中的第一项。 then回调() => Promise.reject('error2')被执行。这会创建一个新的,被拒绝的承诺,因此将拒绝添加到队列中

    • 队列= [承诺。然后拒绝了#1,答应。然后拒绝了#2]
  • 提取并处理队列中的第一项。这是拒绝,因此执行了catch回调console.log。这将输出“ error1”并创建一个新的,已解决的承诺(具有未定义的值)。队列

    • 队列= [承诺。然后#2被拒绝,诺言。然后捕获#1已解决]

...等等

答案 2 :(得分:0)

我不确定在任何地方都指定了不相关的Promise的确切执行顺序,即使这样,如果这对您很重要,您可能想在这两个Promise之间引入一些显式的顺序依赖关系。

但这是一种可能的可能性序列:

  • 第一步:两个诺言都已解决
  • 第二步:被解决,两个诺言都履行了他们的第一个then。这导致两者均被拒绝。我不会依赖于这两个相对于彼此执行的顺序。
  • 第三步:被拒绝,两个诺言都履行了第二个catch/then。我不会依赖于这两个相对于彼此执行的顺序。

您可以大概可以按顺序执行这些步骤(因为它遵循将这些回调提交给调度程序的排队顺序),但这看起来还是有风险的。

如果要让continue1发生在error2之前,则必须安排等待前者完成的代码。