Microtasks
On this page
JavaScript Microtasks (JavaScript微任务)
JavaScript promises use the microtask queue for running callbacks. This chapter is dedicated to the exploration of microtasks in JavaScript. (JavaScript承诺使用微任务队列运行回调。本章专门探讨JavaScript中的微任务。)
Before getting to microtasks it is useful to define JavaScript tasks. (在开始微任务之前,定义JavaScript任务非常有用。)
A task is considered a JavaScript code that is scheduled to be executed by standard mechanisms. For instance, beginning to run a program, an event callback that is being executed, a timeout or an interval that is being fired. They are scheduled in the queue of the task. (任务被视为计划由标准机制执行的JavaScript代码。例如,开始运行程序、正在执行的事件回调、超时或正在触发的间隔。它们被安排在任务队列中。)
A microtask is a brief function that is run after the function or program that created its exits and merely when the execution stack of JavaScript is empty but before returning the control to the event loop. (微任务是在创建其退出的函数或程序之后运行的简短函数,仅在JavaScript的执行堆栈为空但将控件返回到事件循环之前运行。)
As you may already know, promise handlers such as .then, .catch, and .finally are known as asynchronous. (您可能已经知道, .then、.catch和.finally等promise处理程序称为异步。)
Even once a promise is considered resolved, the code placed on the lines below these handlers still runs before them, like here:
let promise = Promise.resolve();
promise.then(() => console.log("promise done!"));
console.log("code finished"); // this show appears first
Invoking it will first show code finished and then promise done. That is not normal behavior as the promise should be done at the start. To find out what is going go further. (调用它将首先显示代码已完成,然后显示承诺已完成。这不是正常的行为,因为承诺应该在开始时完成。要了解具体情况,请更进一步。)
Microtasks Queue
Microtasks Queue (微任务队列)
It is necessary to manage asynchronous tasks properly. (有必要正确管理异步任务。)
Once a promise is ready, the .then/catch/finally handlers are placed in a queue but without executing. When the JavaScript engine gets free from the code, its task is now to execute it. (一旦promise准备就绪, .then/catch/finally处理程序将被放置在队列中,但不执行。当JavaScript引擎从代码中解放出来时,它的任务现在是执行它。)
In case of the presence of a chain with different .then/catch/finally, each of them runs asynchronously. (如果存在具有不同.then/catch/finally的链,则每个链都异步运行。)
If you want to urge code finished execute after promise done, you can place it into the que along with .then, like this:
Promise.resolve()
.then(() => console.log("promise done"))
(.then (() = > console.log ("promise done")))
.then(() => console.log("code finished"));
So, the order can be regarded as intended. (因此,订单可以被视为预期。)
Unhandled Rejection
Unhandled Rejection (未处理的拒绝)
The unhandled rejection can happen in case a promise error can’t be handled at the end of the microtask queue. (如果无法在微任务队列末尾处理promise错误,则可能会发生未处理的拒绝。)
As a rule, the .catch handler is added to the promise chain for handling an expected error:
let promise = Promise.reject(new Error("Promise failed"));
promise.catch(err => console.log('caught'));
// does not run: error handled
window.addEventListener('unhandledrejection', event => console.log(event.reason));
But, missing out to add the .catch will make the engine trigger the event, like here:
<!DOCTYPE html>
<html>
<title>Title of the document</title>
<head></head>
<body>
<script>
let promise = Promise.reject(new Error("Promise failed"));
// Promise failed
(//Promise失败)
window.addEventListener('unhandledrejection', event => alert(event.reason));
</script>
</body>
</html>
Also, the error can be handled later, as follows:
<!DOCTYPE html>
<html>
<title>Title of the document</title>
<head></head>
<body>
<script>
let promise = Promise.reject(new Error("Promise failed"));
setTimeout(() => promise.catch(err => alert('caught')), 1000);
// Error: Promise failed
window.addEventListener('unhandledrejection', event => alert(event.reason));
</script>
</body>
</html>
Running it will lead to Promise failed first and then to caught. (运行它将导致Promise先失败,然后被捕获。)
As we described above, unhandledrejection is created when the microtask queue is complete. The engine investigates the promises. In case of detecting a rejected one, the event occurs. (如上所述,当微任务队列完成时会创建unhandledrejection。发动机调查承诺。如果检测到被拒绝的事件,则会发生事件。)
In the case, demonstrated above, the .catch handler added by setTimeoutoccurs too. But, it triggers after unhandledrejection, hence nothing is changed. (在上面的示例中, setTimeoutoccurs也添加了.catch处理程序。但是,它在未经处理的拒绝后触发,因此没有任何变化。)
Summary
Summary (概要)
The promise handling process is always asynchronous because all the promise actions pass through the internal microtask queue. (Promise处理过程始终是异步的,因为所有Promise操作都通过内部微任务队列。)
The handlers such as .then/catch/finally should be called after the current code is over. To make sure that these handlers are executed, it is required to add them to the .then call. (应在当前代码结束后调用.then/catch/finally等处理程序。 为了确保这些处理程序得到执行,需要将它们添加到.then调用中。)
The microtasks concepts in JavaScript are closely linked to the event loop macrotasks, as well. (JavaScript中的微任务概念也与事件循环宏任务密切相关。)