(js中的MacroTask)
1. Rendering never happens while the engine executes a task. Doesn’t matter if the task takes a long time. Changes to DOM are painted only after the task is complete.
当执行一个task的时候,不会渲染,不管task会执行多久,DOM的渲染会在task执行之后才进行
2. a task takes too long, the browser can’t do other tasks, process user events, so after a time it raises an alert like “Page Unresponsive” suggesting to kill the task with the whole page. That happens when there are a lot of complex calculations or a programming error leading to infinite loop
如果一个task占用时间太长了,浏览器还不能处理其他的task,处理用户事件,一般浏览器会弹出未响应的提示
用例1: splitting CPU-hungry tasks
let i = 0;
let start = Date.now();
function count() {
// do a heavy job
for (let j = 0; j < 1e9; j++) {
i++;
}
alert("Done in " + (Date.now() - start) + ‘ms‘);
}
count();
从1计时到1e9,当运行的时候,点浏览器中的按钮是无响应的。
然后我们把这个任务split开:
let
i
=
0
;
let
start
=
Date
.
now
();
function
count
()
{
// do a piece of the heavy job (*)
do
{
i
++
;
}
while
(
i
%
1e6
!=
0
);
if
(
i
==
1e9
)
{
alert
(
"Done in "
+
(
Date
.
now
()
-
start
)
+
‘ms‘
);
}
else
{
setTimeout
(
count
);
// schedule the new call (**)
}
}
count
();
- First run counts: i=1...1000000.
- Second run counts: i=1000001..2000000.
- …and so on.
现在我们用setTimeout把这个cpu heavy的task间隔开,在周期性执行的间隔中,js引擎就可以去做别的事情,不至于未响应了,而且,总的计时几乎没有变化。
Finally, we’ve split a CPU-hungry task into parts – now it doesn’t block the user interface. And its overall execution time isn’t much longe
用例2: progress indication
div
id
="
progress
"></
div
>
<
script
>
function
count
()
{
for
(
let
i
=
0
;
i
<
1e6
;
i
++
)
{
i
++
;
progress
.
innerHTML
=
i
;
}
}
count
();
</
script
>
浏览器会过一段时间才显示出i的内容。
<
div
id
="
progress
"></
div
>
<
script
>
let
i
=
0
;
function
count
()
{
// do a piece of the heavy job (*)
do
{
i
++
;
progress
.
innerHTML
=
i
;
}
while
(
i
%
1e3
!=
0
);
if
(
i
<
1e7
)
{
setTimeout
(
count
);
}
}
count
();
</
script
>
现在浏览器中会显示出进度。
用例3: doing something after the event
menu
.
onclick
=
function
()
{
// ...
// create a custom event with the clicked menu item data
let
customEvent
=
new
CustomEvent
(
"menu-open"
,
{
bubbles
:
true
});
// dispatch the custom event asynchronously
setTimeout
(()
=>
menu
.
dispatchEvent
(
customEvent
));
};
在event handler中我们希望推迟一些action,直到事件最后冒泡到所有层,我们可以通过将代码包裹在setTimeout中,这会使click事件完全处理完毕后才进行。
Macrotasks和Microtasks
microtasks 一般由promises创建: .then/catch/finally 的handler都是microstask,
await后面跟的也是microtask。
还有一个函数是queueMicrotask(func),将func放到microtask队列中
当执行完一个macrotask后,引擎会执行所有的microtask任务,然后才执行渲染和macrotask的操作
这很重要,因为他确保了执行这些microtask时当前的应用程序环境是相同的(没有鼠标事件, 没有新的网络数据等)在这些microtask间
如果我们想异步执行一个函数,但是在新的渲染前,或者新的event触发前,我们可以用queueMicrotask
div
id
="
progress
"></
div
>
<
script
>
let
i
=
0
;
function
count
()
{
// do a piece of the heavy job (*)
do
{
i
++
;
progress
.
innerHTML
=
i
;
}
while
(
i
%
1e3
!=
0
);
if
(
i
<
1e6
)
{
queueMicrotask
(
count
);
}
}
count
();
</
script
>
这段代码和上面一样,但是用的queueMicrotask来替代setTimeout,所以会在最后才渲染出来。
总结:
The more detailed algorithm of the event loop (though still simplified compare to the specification):
- Dequeue and run the oldest task from the macrotask queue (e.g. “script”).
- Execute all microtasks:
- While the microtask queue is not empty:
- Dequeue and run the oldest microtask.
- Render changes if any.
- If the macrotask queue is empty, wait till a macrotask appears.
- Go to step 1.
To schedule a new macrotask:
- Use zero delayed setTimeout(f).
That may be used to split a big calculation-heavy task into pieces, for the browser to be able to react on user events and show progress between them.
Also, used in event handlers to schedule an action after the event is fully handled (bubbling done).
To schedule a new microtask
- Use queueMicrotask(f).
- Also promise handlers go through the microtask queue.
There’s no UI or network event handling between microtasks: they run immediately one after another.
So one may want to queueMicrotask to execute a function asynchronously, but within the environment state.
Web Workers
For long heavy calculations that shouldn’t block the event loop, we can use Web Workers.
That’s a way to run code in another, parallel thread.
Web Workers can exchange messages with the main process, but they have their own variables, and their own event loop.
Web Workers do not have access to DOM, so they are useful, mainly, for calculations, to use multiple CPU cores simultaneously.
原文地址:https://www.cnblogs.com/eret9616/p/12579407.html