首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaScript任务调度、宏任务和微任务

JavaScript任务调度、宏任务和微任务
EN

Stack Overflow用户
提问于 2017-07-03 02:26:23
回答 1查看 642关注 0票数 0

来自杰克·阿奇博尔德的博客

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

HTML:

代码语言:javascript
复制
<div class="outer">
  <div class="inner"></div>
</div>

联署材料:

代码语言:javascript
复制
// 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运行这段代码时,我得到的结果是

代码语言:javascript
复制
click
mutate
click
mutate
promise
promise
timeout
timeout

我很想看看是怎么回事。执行应该是

  1. First Handler (宏任务)
  2. 处理所有微任务
  3. 第二个Handler (宏任务)
  4. 处理所有微任务
  5. SetTimeout (宏任务)
  6. SetTimeout (宏任务)

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

代码语言:javascript
复制
click
promise
mutate
click
promise
mutate
timeout
timeout

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-03 02:44:07

单击元素时,自然会首先输出click,因为它上有一个单击事件处理程序, first 中的单词' click‘的日志将发生在click事件处理程序函数中。

接下来是setTimeout(function() {}, 0);。这会暂停JavaScript的执行,就像C中的线程/进程生成一样,它直到稍后才会执行,所以我们稍后再讨论。

因为您实际上并没有按照承诺做任何事情,所以它立即解决了,注销了第二个

变异发生在第三次,因为DOM是从上到下读取的,并且在承诺解决后直接突变data-random属性。

最后,既然DOM已被读取完毕,超时将完成第四次

timeout会从内部<div>记录两次,这是因为单独的执行上下文到调用它的位置。这可以通过一个onclick中的而不是提供与setTimeout(function() {console.log(this)}, 0);相同的上下文来看出。由于鼓泡与延迟的setTimeout一起使用,它尝试首先从子<div>触发,然后从父级 <div> (严格地说是您单击的)触发。

因此,您将得到以下结果:

代码语言:javascript
复制
click
promise
mutate
timeout
timeout

clickpromisemutate日志总是一个接一个地出现,乘以您同时单击的元素数。timeout日志总是最后一个。

代码语言:javascript
复制
// 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);
代码语言:javascript
复制
<div class="outer">Outer
  <div class="inner">Inner</div>
</div>

请注意,不同的浏览器处理这些内容的方式不同。由于代码逻辑,我认为假设(我的答案是基于Chrome的)正确处理这个问题。

Firefox在承诺之前处理突变:

代码语言:javascript
复制
click
mutate
promise
promise
timeout
timeout

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

代码语言:javascript
复制
click
mutate
timeout
promise
timeout
promise

IE根本无法处理承诺,抛出语法错误。

希望这会有帮助!)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44876964

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档