【问题标题】:Out of Order Promise乱序承诺
【发布时间】:2017-03-07 19:27:42
【问题描述】:

鉴于以下code

p = () ->
  foo 5
  new Promise( (resolve, reject) ->
    console.log 'in promise'
    resolve 'done'
  )

foo = (n) ->
  console.log n
  if(n <= 0) then 0 else foo (n-1)

然后我称之为:

p().then (-&gt; console.log 'hi'), (-&gt; console.log 'there')

输出显示:

5
4
3
2
1
0
in promise
hi

首先,如果我希望p 的整个主体出现在同一个Promise 中,我必须将它包装在new Promise ( (resolve, reject) ) -&gt; ... ) 中吗?

其次,是否有可能通过修改foo,使hi5/4/3/2/1/0in promise 之前打印?

最后,在什么情况下then的成功案例会在p()主体完全完成之前执行?

【问题讨论】:

  • "首先,如果我想让p 的整个主体出现在同一个Promise 中,我必须将它包装在new Promise ( (resolve, reject) ) -&gt; ... ) 中吗?"我不明白这个问题。任何直接在p 内部的东西都会在你调用p 时执行。如果您在 Promise 回调中放置任何代码,该代码将异步执行。
  • 你为什么要使用 Promise?您的整个代码是同步的。如果您的实际用例是异步的,请向我们展示您的真实代码。
  • 你好像真的在找p = () -&gt; new Promise (resolve) -&gt; { console.log 'in promise'; foo 5; resolve 'done' }

标签: javascript coffeescript promise


【解决方案1】:

首先,如果我希望 p 的整个主体出现在同一个 Promise 中,我必须将它包装在 new Promise ( (resolve, reject) ) -> ... ) 中吗?

嗯,是的。如果您希望p 的整个主体发生在同一个promise 中,那么您必须将p 的整个主体放在同一个promise 中。但是,正如 Bergi 在 cmets 中提到的,这仍然不会影响您的整体代码行为。 Promise 构造是一个同步过程,这意味着一旦您创建了 Promise,其主体中的代码就会运行。稍后发生的部分是承诺解决方案(成功或失败)。

p = () ->
  foo 5                             // happens synchronously
  new Promise( (resolve, reject) ->
    console.log 'in promise'        // happens synchronously
    resolve 'done'                  // happens asynchronously
  )

下面的代码是等价的:

p = () -> 
  new Promise( (resolve, reject) ->
    foo 5                           // happens synchronously
    console.log 'in promise'        // happens synchronously
    resolve 'done'                  // happens asynchronously
  )

如果您提供更具体的用例,我也许可以给出更具体的答案。

其次,是否有可能通过修改 foo,hi 将在 5/4/3/2/1/0 之前或承诺打印?

承诺解决,按照规范,总是异步发生(在事件循环中以microtasks 的形式)。这意味着所有同步代码,例如foo 中的循环,必须在任何承诺解决之前完成。

引用Jake Archibald

微任务通常安排在当前执行的脚本之后应该立即发生的事情,例如对一批操作做出反应,或者在不承担全新任务的情况下进行异步操作。只要没有其他 JavaScript 在中间执行,微任务队列就会在回调之后处理,并且在每个任务结束时处理。在微任务期间排队的任何其他微任务都将添加到队列的末尾并进行处理。微任务包括突变观察者回调,和上面的例子一样,承诺回调。

因此,让foo 中的事情发生在p 中的事情之后的唯一方法是强制foo异步运行 p 完成之后运行。

解决这个问题的一种方法是使用setTimeoutp 中的Promise 解决后延迟foo 的代码。之所以可行,是因为setTimeout 在事件循环的下一次迭代中安排了一个常规任务,而微任务(以及因此的承诺)被指定在事件循环的同一迭代中运行。

这是一个 JS 演示:

注意:这可能不适用于所有浏览器。我在 Chrome 版本 54.0.2840.71 中对其进行了测试。 Jake 的文章有更多关于特定浏览器错误的详细信息。

const foo = (n) => {
  setTimeout(() => {
    console.log(n);
    if (n <= 0) {
      return 0;
    } else {
      return foo(n - 1);
    }
  });
}

const p = () => {
  foo(5);
  return new Promise((resolve) => {
    console.log('in promise');
    resolve('done');
  });
}

p().then(() => console.log('hi'));

/* Output:

in promise
hi
5
4
3
2
1
0
*/

最后,在什么情况下 then 的成功案例会在 p() 主体完全完成之前执行?

在任何情况下,因为p().then 的成功案例取决于该内部承诺。在我们调用 then 的 Promise 被解析(成功或失败)之前,无法调用传递给 then 的成功回调。

这里是another useful article,关于在编写 JS 框架时解决这些时间问题。

【讨论】:

  • 不,"in promise" 实际上不会异步发生。
  • 你是对的,我会澄清的。只有 hi 的日志记录是异步的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 2017-12-07
  • 2017-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多