首页 > 解决方案 > 在不同的函数调用语法中,承诺的控制流如何在 javascript 中导航

问题描述

我有doSomething, doSomethingElse&finalHandler功能如下:

function doSomething() {
  console.log('doSomething(): start');
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log('doSomething(): end');
      resolve();
    }, 1000);
  });
}

function doSomethingElse() {
  console.log('doSomethingElse(): start');
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log('doSomethingElse(): end');
      resolve();
    }, 1000);
  });
}

function finalHandler() {
  console.log('finalHandler(): start');
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log('finalHandler(): end');
      resolve();
    }, 1000);
  });
}

我有一个example1看起来像这样的函数:

function example1() {
  doSomething().then(function () {
    return doSomethingElse();
  }).then(finalHandler);
}

正在返回

doSomething(): start
doSomething(): end
doSomethingElse(): start
doSomethingElse(): end
finalHandler(): start
finalHandler(): end

我有example2

function example2() {
  doSomething().then(function () {
    doSomethingElse();
  }).then(finalHandler);
}

返回:

doSomething(): start
doSomething(): end
doSomethingElse(): start
finalHandler(): start
doSomethingElse(): end
finalHandler(): end

并且example3

function example3() {
  doSomething().then(doSomethingElse())
    .then(finalHandler);
}

返回:

doSomething(): start
doSomethingElse(): start
doSomething(): end
finalHandler(): start
doSomethingElse(): end
finalHandler(): end

并且example4

function example4() {
  doSomething().then(doSomethingElse)
    .then(finalHandler);
}

返回:

doSomething(): start
doSomething(): end
doSomethingElse(): start
doSomethingElse(): end
finalHandler(): start
finalHandler(): end

我可以理解不同的函数调用语法会给出不同的结果——但是这种行为背后的概念是什么?

我不是在寻找更正或优化的代码。我想知道如何使用不同的语法导航流程?

标签: javascriptpromise

解决方案


这里的概念 -

  1. 任务是微任务队列将在一个执行上下文结束时耗尽,然后从宏任务队列中挑选任务。
  2. 已解决的承诺回调是一个微任务。
  3. setTimeout 的回调是一个宏任务。
  4. 被链接的 then 只会等待 previous then,如果 previous then 会返回一个 Promise。如果它是除了承诺之外的任何东西,那么下一个 then 将不会等待上一个 then。
  5. 传递对函数的引用与调用函数不同。例如1

doSomething() 进入调用堆栈 -> doSomething(): start print 它返回一个承诺,该承诺将在 1 秒后解决,然后将调用“then”处理程序。由于没有解决的承诺或任务,程序返回。如果您在 chrome 中执行,您可以使用未定义的打印来验证。1 秒后,第一个 Promise 被解决,在 doSomething 中排队。如语句 console.log(' doSomething(): end '); 是同步的,它会被打印出来。

.then(function () {
    return doSomethingElse();
  })

现在执行。与上面相同的流程 - console.log('doSomethingElse(): start'); --> 1 秒后 doSomethingElse end 与最后一个 then 相同:console.log('finalHandler(): start'); --> 1 秒后 console.log('finalHandler(): end');

示例 2 与示例 1的不同之处在于,在第一个示例中,doSomethingElse 返回了一个承诺。之后的 then 链接将等待在执行之前解决该承诺。但在示例 2 中,即使 doSomethingElse 返回一个承诺,我们也不会在 then 处理程序回调中返回它,这就是为什么将执行 doSomethingElse 和 setTimeout 的事件将为 doSomethingElse(): end 设置,then for final 处理程序将立即执行,因为它不会等待前一个承诺被解决。只有在之前重新调整了一个承诺时,它才会等待。因此finalHandler(): start首先打印。之后,doSomethingElse 超时和 finalHandler 超时的计时器都会到期,但之前的超时将在任务队列中排在第一位,因此它会首先被打印。

关于不同的格式.. 当您执行.then(doSomethingElse)时,您传递的是对该函数的引用,因此与您在 then.then() 中复制 doSomethingElse 的完整代码相同。它是一个有效的回调。但是当你执行.then(doSomethingElse())时,它只是执行函数 doSomethingElse,但它不是回调,所以没有得到任何回调,它只是未定义,因此链中的下一个 then 被执行。

剩下的两个例子现在应该是不言自明的了。


推荐阅读