micro task 和 macro task

(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.

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

时间: 2024-11-09 05:35:14

micro task 和 macro task的相关文章

MapReduce作业的map task和reduce task调度参数

MapReduce作业可以细分为map task和reduce task,而MRAppMaster又将map task和reduce task分为四种状态: 1.pending:刚启动但尚未向resourcemanager发送资源请求: 2.scheduled:已经向resourceManager发送资源请求,但尚未分配到资源: 3.assigned:已经分配到了资源且正在运行: 4.completed:已经运行完成. map task的生命周期为:scheduled -> assigned -

.Net4.0如何实现.NET4.5中的Task.Run及Task.Delay方法

前言 .NET4.0下是没有Task.Run及Task.Delay方法的,而.NET4.5已经实现,对于还在使用.NET4.0的同学来说,如何在.NET4.0下实现这两个方法呢? 在.NET4.0下,有一个泛型类,叫TaskCompletionSource<TReuslt>,它能控制Task的行为,如给Task设置结果.设置异常.设置取消等. MSDN是这样描述的(网址): 表示未绑定到委托的 Task<TResult> 的制造者方,并通过Task属性提供对使用者方的访问. 它有以

Task.Run vs Task.Factory.StartNew

Task.Run 和 Task.Factory.StartNew 都可以把一段要执行的代码放到ThreadPool thread中去执行.Task.Factory.StartNew是.Net 4.0中引入的,而Task.Run则是在.Net 4.5中引入,首要目的是为了简化Task.Factory.StartNew的使用.简言之, Task.Run(someAction) 与 Task.Factory.StartNew(someAction, CancellationToken.None, Ta

C# Task的使用---Task的启动

.NET 4.0包含的新名称空间System.Threading.Tasks,它包含的类抽象出了线程功能.任务表示应完成的某个单元的工作.这个单元的工作可以在单独的线程中运行,也可以以同步的方式启动一个任务,这需要等待主调线程.使用任务不仅可以获得一个抽象层,还可以对底层线程进行许多控制. 启动任务 1).使用TaskFactory类的实例,在其中把TaskMethod()方法传递给StartNew方法,就会立即启动任务. 1: using System; 2: using System.Col

Task.Run 和 Task.Factory.StartNew

在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至控制任务的调度行为.所有这些能力也带来了复杂性的提升,你必须知道何时应该使用何种重载方法,提供哪种调度方式等等.并且Task.Factory.StartNew这种写法也不够简洁明快,至少对它使用的主要场景不够快,一般它使用的主要场景只是将一个工作任务丢给一个后台线程执行而已. 于是,在.NET Fr

Task.Run 和Task.Factory.StartNew 区别

.Net Framework 4.0开始支持Task.Factory.StartNew,.Net Framework 4.5后开始支持Task.Run. Task.Factory.StartNew经过简化成了Task.Run,注意的是Factory.StartNew的方法参数种类更丰富,可以完成多样的需求. 在选择上,如果创建的线程需要长时间运行的话那就选择Task.Factory.StartNew. 一:使用 Task.Run(() =>{......}); Task.Factory.Star

Task.Run 和 Task.Factory.StartNew 区别

Task.Run 是在 dotnet framework 4.5 之后才可以使用, Task.Factory.StartNew 可以使用比 Task.Run 更多的参数,可以做到更多的定制. 可以认为 Task.Run 是简化的 Task.Factory.StartNew 的使用,除了需要指定一个线程是长时间占用的,否则就使用 Task.Run 创建新线程 下面来告诉大家使用两个函数创建新的线程 Task.Run(() => { var foo = 2; }); 这时 foo 的创建就在另一个线

Windows 商店应用程序异步执行task和调整task优先级

在制作WP8.1手电筒的时候遇到一个问题,手电筒有时候能够点亮有时候点不亮. 在MSDN论坛上面有人告诉我可能是优先级的问题示意叫我使用CoreDispatcher 将task任务提高权限,但是发现还是不行. 后来发现点亮闪关灯需要在UI线程中触发,不能再异步中实现,感觉和画图有点类似不能在非主线程中绘制图片. 下面我就分享怎么利用CoreDispatcher改变task任务的优先级(不过还没有验证,因为我还没有遇到需要改变优先级的task,但是依据Windows运行时API的说明应该是正确的改

hadoop 分片与分块,map task和reduce task的理解

分块:Block HDFS存储系统中,引入了文件系统的分块概念(block),块是存储的最小单位,HDFS定义其大小为64MB.与单磁盘文件系统相似,存储在 HDFS上的文件均存储为多个块,不同的是,如果某文件大小没有到达64MB,该文件也不会占据整个块空间.在分布式的HDFS集群上,Hadoop系统保证一个块存储在一个datanode上. 把File划分成Block,这个是物理上真真实实的进行了划分,数据文件上传到HDFS里的时候,需要划分成一块一块,每块的大小由hadoop-default.