【问题标题】:Why does my function execute before my promise callback?为什么我的函数在我的 promise 回调之前执行?
【发布时间】:2018-03-10 23:12:34
【问题描述】:

为什么在我的 Promise 之后调用的函数在 Promise 的回调之前执行?

我在 MDN 上看过这个,但没看懂

"回调将永远不会在当前完成之前被调用 JavaScript 事件循环的运行。”

我认为这意味着如果我在resolve()reject() 之后有任何其他语句,它们将在调用回调之前执行。不过,这似乎是一个不完整的理解。

function myFunction() {
  return new Promise( function(resolve, reject) {

    const err = false;

    if(err) {
      reject("Something went wrong!!!");
    }
    else {
      resolve("All good");
    }
  });
}

myFunction().then(doSuccess).catch(doError);
doOther();

function doError(err) {
  console.log(err);
}

function doSuccess() {
  console.log('Success');
}

function doOther() {
  console.log("My Other Function");
}

输出:

我的其他功能

成功

【问题讨论】:

  • 这正是你所观察到的; doOther 在当前运行中执行,因此回调将永远在它之前被调用。
  • 您的问题适用于 promise .then() 回调,而不是一般的回调。有很多回调是同步调用的,比如你传递给array.filter()的回调。

标签: javascript promise


【解决方案1】:

按照规范,promise .then().catch() 回调永远不会同步调用,而是在事件循环的未来滴答声中调用。这意味着其余的同步代码总是在调用任何.then() 处理程序之前运行。

因此,您的 doOther() 函数在调用 doSuccess()doError() 之前运行。

Promise 是这样设计的,因此无论 Promise 是立即解决还是将来某个时间解决,都会以一致的时间调用 Promise .then() 处理程序。如果允许同步 .then() 处理程序,那么调用代码要么必须知道它何时可能被同步调用,否则您将容易受到奇怪的计时错误的影响。

在 ES6 规范中的承诺所基于的 Promises/A+ specification 中,它定义了一个 `.then() 处理程序,如下所示:

promise.then(onFulfilled, onRejected)

然后是这样说的:

2.2.4。在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled 或 onRejected。 [3.1]。

然后,它定义了这样的平台代码:

这里的“平台代码”是指引擎、环境和承诺实现代码。在实践中,此要求确保 onFulfilled 和 onRejected 在调用 then 的事件循环之后异步执行,并使用新堆栈。这可以通过 setTimeout 或 setImmediate 等“宏任务”机制实现,也可以通过 MutationObserver 或 process.nextTick 等“微任务”机制实现。由于 Promise 实现被视为平台代码,它本身可能包含一个任务调度队列或“蹦床”,其中调用了处理程序。

基本上这意味着.then() 处理程序是通过在事件循环中插入一个任务来调用的,该任务在当前运行的 Javascript 完成并将控制权返回给解释器(在那里它可以检索下一个事件)之前不会执行。因此,您在安装 .then() 处理程序之后拥有的任何同步 Javascript 代码将始终在调用 .then() 处理程序之前运行。

【讨论】:

  • 感谢超级详细的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-01
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 2020-07-13
相关资源
最近更新 更多