Javascript事件循环机制以及渲染引擎何时渲染UI

原文链接:https://segmentfault.com/a/1190000013212944

实际运行发现有两点和文章说的不一样:

  1. 不管在哪种任务里出现了UI的修改(包括添加节点、修改颜色、修改节点内容等),UI渲染会立即执行(在debugger状态下能看到),不会等到任务队列执行完毕
    【更正:UI的修改(包括添加节点、修改颜色、修改节点内容等),会立即更新应用程序的状态。微任务队列清空后,事件循环会检查当前是否需要重新渲染UI,如果需要则渲染UI视图。debugger状态可能在微任务队列中强行插入了一个是否需要重新渲染UI视图的任务,所以在断点处也能看到UI被重新渲染】
  2. MutationObserver的callback回调函数是异步的,只有在全部DOM操作完成之后才会调用callback(参考)。也就是说,不管是用户点击事件onclick,还是js触发的click,执行的结果是一样的,只会触发一个mutate。

还有一点需要注意,如果没有debugger,那么在alert(‘锚点’)的时候,看到inner的内容其实还是begin而不是end,我想这跟alert的阻断也有关系(参考)

var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
 
var i = 0;
 
// Let's listen for attribute changes on the
// outer element
new MutationObserver(function() {
    debugger
    console.log('mutate');
}).observe(outer, {
    attributes: true
});
 
// Here's a click listener…
function onClick() {
    i++;
 
    if(i === 1) {
        inner.innerHTML = 'end';
        debugger
    }
 
    console.log('click');
 
    setTimeout(function() {
        alert('锚点');
        inner.style.backgroundColor = 'green';
        console.log('timeout');
        debugger
    }, 0);
 
    Promise.resolve().then(function() {
        console.log('promise');
        inner.appendChild(document.createElement('span'));
        debugger
    });
 
 
    outer.setAttribute('data-random', Math.random());
    debugger
}
 
// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

输出:

click
click
promise
mutate
promise
timeout
timeout

另外还有这个:

document.body.style.backgroundColor = 'green'
while(true) {}
body颜色会变绿色吗

document.body.style.backgroundColor = 'red'
setTimeout(() => {
	while(true) {}
})
body颜色会变红色吗

document.body.style.backgroundColor = 'yellow'
Promise.resolve().then(() => {
		while(true) {}
})
body颜色会变黄吗

直接在浏览器运行,只有第二条会变颜色,其它2条会直接卡死,可是如果在死循环前加上debugger,那么会发现其实以上三种情况下,body的颜色都已经被改变了。

inner.style.backgroundColor = 'green';
while(true){
  debugger
}
setTimeout(() => {
    debugger
    while(true) {}
})
Promise.resolve().then(() => {
    debugger
    while(true) {}
})

在微任务队列清空后,事件循环会检查当前是否需要重新渲染UI,如果需要则渲染UI视图。

宏任务

宏任务包含创建文档对象、解析HTML、执行主线JavaScript代码、更改当前URL以及各种事件,例如页面加载、输入、网络事件和定时器等等。宏任务运行完成后,浏览器继续其他的任务调度,如重新渲染页面或者垃圾回收。

微任务

微任务包括promise、回调函数、DOM发生变化等。微任务更新应用程序的状态,必须在浏览器任务继续执行其他任务(渲染UI视图或者进行下一个宏任务)之前执行。

重点参考:深入理解JavaScript之Event Loop

你可能感兴趣的:(沉淀)