繁体   English   中英

JavaScript任务计划,宏任务和微任务

[英]JavaScript task scheduling, Macrotask and Microtasks

杰克·阿奇博尔德Jake Archibald )的博客

小提琴(点击嘿): https : //jsfiddle.net/1rpzycLf/

HTML:

<div class="outer">
  <div class="inner"></div>
</div>

JS:

// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

// Let's listen for attribute changes on the
// outer element
new MutationObserver(function() {
  console.log('mutate');
}).observe(outer, {
  attributes: true
});

// Here's a click listener…
function onClick() {
  console.log('click');

  setTimeout(function() {
    console.log('timeout');
  }, 0);

  Promise.resolve().then(function() {
    console.log('promise');
  });

  outer.setAttribute('data-random', Math.random());
}

// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

当为inner div运行此片段时,我得到的结果是

click
mutate
click
mutate
promise
promise
timeout
timeout

我正在努力看情况如何。 执行应该是

  1. 第一处理程序(宏任务)
  2. 处理所有微任务
  3. 第二处理程序(宏任务)
  4. 处理所有微任务
  5. SetTimeout(宏任务)
  6. SetTimeout(宏任务)

考虑到这一点,我期望输出日志:

click
promise
mutate
click
promise
mutate
timeout
timeout

不确定为什么仅在两次单击事件处理程序处理后才执行promises 理想情况下,第一个承诺应该在第一个mutate之后执行,但是我们可以看到事实显然并非如此。 有人知道为什么吗? (使用firefox 54.0)

当您单击该元素时,自然会首先输出click ,因为您上面有一个click事件处理程序,并且单击事件处理函数中首先发生的单词“ click”的日志。

接下来是setTimeout(function() {}, 0); 这暂停了JavaScript的执行,就像C语言中的线程/进程产量一样。它直到稍后才执行,因此我们将稍等一下。

因为你没有真正做什么用的承诺,它解决了瞬间, 第二注销。

因为DOM是从上到下读取的,所以突变发生在第三位 ,并且您在promise解析之后直接对data-random属性进行突变。

最终,既然DOM已经完成读取,那么超时将排在第四位

timeout从内部<div>被记录两次,这是因为从其调用的地方有单独的执行上下文 这可以通过这样的事实可以看出, console.log(this)内的onclick 提供相同的上下文中setTimeout(function() {console.log(this)}, 0); 由于冒泡以及延迟的setTimeout ,它首先尝试从子<div>触发,然后又从 <div> (从技术上单击)触发。

因此,您最终得到:

click
promise
mutate
timeout
timeout

clickpromisemutate日志将总是一个接一个地乘以您同时单击的元素数。 timeout日志将始终排在最后。

 // Let's get hold of those elements var outer = document.querySelector('.outer'); var inner = document.querySelector('.inner'); // Let's listen for attribute changes on the // outer element new MutationObserver(function() { console.log('mutate'); }).observe(outer, { attributes: true }); // Here's a click listener… function onClick() { console.clear(); // Added for clarity console.log('click'); setTimeout(function() { console.log('timeout'); }, 0); Promise.resolve().then(function() { console.log('promise'); }); outer.setAttribute('data-random', Math.random()); } // …which we'll attach to both elements inner.addEventListener('click', onClick); outer.addEventListener('click', onClick); 
 <div class="outer">Outer <div class="inner">Inner</div> </div> 

请注意,不同的浏览器对这些内容的处理方式也不同。 认为 Chrome浏览器(其中我的答案是基于关闭的)正确处理此,由于代码逻辑。

Firefox处理承诺之前的突变:

click
mutate
promise
promise
timeout
timeout

Edge在承诺之前处理变异和超时:

click
mutate
timeout
promise
timeout
promise

IE根本无法处理承诺,会引发语法错误。

希望这可以帮助! :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM