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

JavaScript任务调度、宏任务和微任务,javascript,event-handling,Javascript,Event Handling,来自的博客 小提琴(点击嘿): HTML: 当为内部div运行这篇文章时,我得到的结果是 click mutate click mutate promise promise timeout timeout 我很难明白这是怎么回事。 执行应该是 第一个处理程序(宏任务) 处理所有微任务 第二个处理程序(宏任务) 处理所有微任务 设置超时(宏任务) 设置超时(宏任务) 考虑到这一点,我希望日志输出: click promise mutate click promise mutate timeout

来自的博客

小提琴(点击嘿):

HTML:

当为
内部div运行这篇文章时,我得到的结果是

click
mutate
click
mutate
promise
promise
timeout
timeout
我很难明白这是怎么回事。 执行应该是

  • 第一个处理程序(宏任务)
  • 处理所有微任务
  • 第二个处理程序(宏任务)
  • 处理所有微任务
  • 设置超时(宏任务)
  • 设置超时(宏任务)
  • 考虑到这一点,我希望日志输出:

    click
    promise
    mutate
    click
    promise
    mutate
    timeout
    timeout
    

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

    当您单击元素时,自然会首先输出
    click
    ,因为它上面有一个click事件处理程序,并且在click事件处理程序函数中的first事件中记录单词“click”

    接下来是
    setTimeout(函数(){},0)。这会暂停JavaScript的执行,就像C中的线程/进程产出一样。它要到稍后才会执行,所以我们稍后再讨论这个问题

    因为您实际上并没有对承诺做任何事情,所以它会立即解决,第二次退出

    突变发生在第三个中,因为DOM是从上到下读取的,并且在承诺解析后直接对
    data random
    属性进行突变

    最后,既然DOM已经被读取完毕,那么超时将在第四次读取时结束

    由于到调用它的位置,
    超时从内部
    记录两次。这可以从以下事实中看出:
    console.log(This)
    onclick
    中提供与
    setTimeout相同的上下文(function(){console.log(This)},0)。由于与延迟的
    设置超时一起,它会尝试先从子
    触发,然后从父触发(技术上单击)

    因此,您最终会:

    click
    promise
    mutate
    timeout
    timeout
    
    单击
    承诺
    变异
    日志总是一个接一个地出现,乘以您同时单击的元素数。
    超时
    日志始终排在最后

    //让我们抓住那些元素
    var outer=document.querySelector('.outer');
    var inner=document.querySelector('.inner');
    //让我们听一听屏幕上的属性更改
    //外部元素
    新的MutationObserver(函数(){
    console.log('mutate');
    }).观察(外部、{
    属性:true
    });
    //这里有一个点击侦听器…
    函数onClick(){
    console.clear();//为了清晰起见添加了
    console.log('click');
    setTimeout(函数(){
    log('timeout');
    }, 0);
    Promise.resolve().then(函数()){
    console.log(“承诺”);
    });
    outer.setAttribute('data-random',Math.random());
    }
    //…我们将附加到这两个元素
    inner.addEventListener('click',onClick);
    outer.addEventListener('click',onClick)
    
    外部
    内部的
    
    当您单击元素时,自然会首先输出
    click
    ,因为它上面有一个click事件处理程序,并且在click事件处理程序函数中的first事件中有“click”一词的日志

    接下来是
    setTimeout(函数(){},0)。这会暂停JavaScript的执行,就像C中的线程/进程产出一样。它要到稍后才会执行,所以我们稍后再讨论这个问题

    因为您实际上并没有对承诺做任何事情,所以它会立即解决,第二次退出

    突变发生在第三个中,因为DOM是从上到下读取的,并且在承诺解析后直接对
    data random
    属性进行突变

    最后,既然DOM已经被读取完毕,那么超时将在第四次读取时结束

    由于到调用它的位置,
    超时从内部
    记录两次。这可以从以下事实中看出:
    console.log(This)
    onclick
    中提供与
    setTimeout相同的上下文(function(){console.log(This)},0)。由于与延迟的
    设置超时一起,它会尝试先从子
    触发,然后从父触发(技术上单击)

    因此,您最终会:

    click
    promise
    mutate
    timeout
    timeout
    
    单击
    承诺
    变异
    日志总是一个接一个地出现,乘以您同时单击的元素数。
    超时
    日志始终排在最后

    //让我们抓住那些元素
    var outer=document.querySelector('.outer');
    var inner=document.querySelector('.inner');
    //让我们听一听屏幕上的属性更改
    //外部元素
    新的MutationObserver(函数(){
    console.log('mutate');
    }).观察(外部、{
    属性:true
    });
    //这里有一个点击侦听器…
    函数onClick(){
    console.clear();//为了清晰起见添加了
    console.log('click');
    setTimeout(函数(){
    log('timeout');
    }, 0);
    Promise.resolve().then(函数()){
    console.log(“承诺”);
    });
    outer.setAttribute('data-random',Math.random());
    }
    //…我们将附加到这两个元素
    inner.addEventListener('click',onClick);
    outer.addEventListener('click',onClick)
    
    外部
    内部的
    
    我不会以你的例子结束。Firefox仍然会记录
    点击
    变异
    点击
    mut
    
    click
    promise
    mutate
    timeout
    timeout