Home >Web Front-end >JS Tutorial >Promises that need to be truly understood

Promises that need to be truly understood

coldplay.xixi
coldplay.xixiforward
2020-09-07 13:30:062106browse

Promises that need to be truly understood

Related learning recommendations: javascript learning tutorial

Promise Regarding API, everyone should be able to use it proficiently, but You may still have knowledge blind spots related to microtasks.

Prerequisite knowledge

Before starting the text, let us first set the tone in advance for some of the content involved in this article.

Promise Which APIs involve microtasks?

In Promise, only callbacks that need to be executed after state changes are involved are considered microtasks, such as then, catch, finally , all other code executions are macro tasks (synchronous execution).

Promises that need to be truly understood

In the above figure, blue indicates synchronous execution and yellow indicates asynchronous execution (thrown into the microtask queue).

When are these microtasks added to the microtask queue?

We look at this issue according to the ecma specification:

  • If the Promise status is pending at this time, then the successful or failed callbacks will be added to [ [PromiseFulfillReactions]] and [[PromiseRejectReactions]]. If you have looked at the handwritten Promise code, you should be able to find that there are two arrays storing these callback functions.

  • If the Promise status is non-pending at this time, the callback will become Promise Jobs, which are microtasks.

After understanding the above knowledge, the main film begins.

The same then, different micro-tasks are executed

Elementary

Promise.resolve()
  .then(() => {    console.log("then1");    Promise.resolve().then(() => {      console.log("then1-1");
    });
  })
  .then(() => {    console.log("then2");
  });复制代码

Everyone should be able to get the correct answer from the above code: then1 → then1 -1 → then2.

Although then is executed synchronously, and the status has also changed. But this does not mean that every time we encounter then, we need to throw its callback into the microtask queue. Instead, we wait for the callback of then to complete and then execute the corresponding callback according to the situation. operate.

Based on this, we can draw the first conclusion: In the chain call, only after the previous then callback is executed, the following Only the callbacks in then will be added to the microtask queue.

Intermediate

Everyone knows that after Promise resolve, the callback in then will immediately enter the microtask queue.

So what do you think the output of the following code will be?

let p = Promise.resolve();

p.then(() => {  console.log("then1");  Promise.resolve().then(() => {    console.log("then1-1");
  });
}).then(() => {  console.log("then1-2");
});

p.then(() => {  console.log("then2");
}); 
复制代码

According to our initial understanding, it is not difficult to conclude that then2 will be output after then1-1, but the actual situation is the opposite.

Based on this, we draw the second conclusion: The beginning of each chain call will first enter the microtask queue in sequence.

Next let’s change the way we write it:

let p = Promise.resolve().then(() => {  console.log("then1");  Promise.resolve().then(() => {    console.log("then1-1");
  });
}).then(() => {  console.log("then2");
});

p.then(() => {  console.log("then3");
});复制代码

The above code actually has a trap, then will return a new Promise every time, at this time p is no longer generated by Promise.resolve(), but by the last then, so then3 should be in then2 is printed after.

By the way, we can also optimize the conclusion we reached before: The beginning of each chain call of the same Promise will first enter the microtask queue in sequence.

Advanced

Can you guess when then1-2 will be printed?

Promise.resolve()
  .then(() => {    console.log("then1");    Promise.resolve()
      .then(() => {        console.log("then1-1");        return 1;
      })
      .then(() => {        console.log("then1-2");
      });
  })
  .then(() => {    console.log("then2");
  })
  .then(() => {    console.log("then3");
  })
  .then(() => {    console.log("then4");
  });复制代码

This question is definitely simple. Remember the first conclusion to get the answer. The following is the analysis:

  • First timeresolve After the first then callback enters the microtask queue and is executed, print then1

  • the second time resolve After the first internal then callback enters the microtask queue, at this time all the external first then callbacks have been executed, and the second external needs to be The then callback is also inserted into the microtask queue.

  • Execute the microtask, print then1-1 and then2, and then add the callbacks in then respectively Insert the microtask queue

  • to execute the microtask and print then1-2 and then3. The following content will not be explained one by one

Next let’s modify return 1, and the result will be quite different:

Promise.resolve()
  .then(() => {    console.log("then1");    Promise.resolve()
      .then(() => {        console.log("then1-1");        return Promise.resolve();
      })
      .then(() => {        console.log("then1-2");
      });
  })
  .then(() => {    console.log("then2");
  })
  .then(() => {    console.log("then3");
  })
  .then(() => {    console.log("then4");
  });复制代码

When we return Promise.resolve( ), guess when then1-2 will be printed?

The answer is the last one printed.

Why is there such a big change in the execution order of microtasks for return different things in then? The following is the author's analysis.

PS:then 返回一个新的 Promise,并且会用这个 Promise 去 resolve 返回值,这个概念需要大家先了解一下。

根据 Promise A+ 规范

根据规范 2.3.2,如果 resolve 了一个 Promise,需要为其加上一个 thenresolve

if (x instanceof MyPromise) {  if (x.currentState === PENDING) {
  } else {
    x.then(resolve, reject);
  }  return;
}复制代码

上述代码节选自手写 Promise 实现。

那么根据 A+ 规范来说,如果我们在 then 中返回了 Promise.resolve 的话会多入队一次微任务,但是这个结论还是与实际不符的,因此我们还需要寻找其他权威的文档。

根据 ECMA - 262 规范

根据规范 25.6.1.3.2,当 Promise resolve 了一个 Promise 时,会产生一个NewPromiseResolveThenableJob,这是属于 Promise Jobs 中的一种,也就是微任务。

This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.

并且该 Jobs 还会调用一次 then 函数来 resolve Promise,这也就又生成了一次微任务。

这就是为什么会触发两次微任务的来源。

最后

文章到这里就完结了,大家有什么疑问都可以在评论区提出。

想了解更多编程学习,敬请关注php培训栏目!

The above is the detailed content of Promises that need to be truly understood. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:learnku.com. If there is any infringement, please contact admin@php.cn delete