码迷,mamicode.com
首页 > 系统相关 > 详细

micro task 和 macro task

时间:2020-03-27 11:10:07      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:mac   long   network   oop   catch   api   start   cut   change   

技术图片

 

(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();


  1. First run counts: i=1...1000000.
  2. Second run counts: i=1000001..2000000.
  3. …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):

  1. Dequeue and run the oldest task from the macrotask queue (e.g. “script”).
  2. Execute all microtasks:
  • While the microtask queue is not empty:
  • Dequeue and run the oldest microtask.
  1. Render changes if any.
  2. If the macrotask queue is empty, wait till a macrotask appears.
  3. 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.

 

micro task 和 macro task

标签:mac   long   network   oop   catch   api   start   cut   change   

原文地址:https://www.cnblogs.com/eret9616/p/12579407.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!