浏览器是一个多进程多线程的应用程序,浏览器内部工件极其复杂,为了减少连环崩溃的几率,当启动浏览器后,它会自动启动多个进程,其中,有以下主要进程:
浏览器主要负责界面显示、用户交互、子进程管理等,浏览器进程内部会启动多个线程处理不同的任务。
网络进程主要加载网络资源,也会启动多线程。
渲染进程启动后,会开启一个渲染主线程,主线程负责执行HTML、CSS、JS代码,在默认情况下,浏览器会为每个标签开启一个新的渲染进程,以保证不同的标签页之间不相互影响。
渲染主线程是浏览器中最繁忙的线程,它要处理的任务包括但不限于:
渲染主线程的任务调度方式是排队,浏览器的任务会进入消息队列(事件队列)
在代码执行过程中,会遇到一些无法立即处理的任务。例如::
如果让渲染主线程等待这些任务的时机达到,就会导致主线程长期处于阻塞的状态,从而导致浏览器卡死。这是浏览器就会使用异步来解决这个问题。
异步的具体做法是当某些任务发生时,比如计时器、网络、事件监听,这是主线程将任务交给其他线程去处理,自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到事件队列的队尾排队,等待主线程调度执行。
任务没有优先级,但事件队列有优先级
在过去的浏览器中,有一个宏队列和一个微队列(VIP),而现在的浏览器中,每个任务都有一个任务类型,同一个类型的任务必须在一个队列中,不同类型的任务可以分属于不同的队列,在一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行,w3c规定,浏览器必须准备好一个微队列(micro task queue),微队列中的任务优先所有其他任务执行。
在目前chrome中有延时队列(中)、交互队列(高)、微队列(最高)等,添加到微队列的主要方式是
Promise.MutationObserver
例如:
Promise.resolve().then(函数); //立即把一个函数加入微队列
Promise.MutationObserver是一个基于Promise对象的封装实现,用于将MutationObserver和Promise结合起来处理DOM树的变化。
MutationObserver是浏览器提供的一个API,用于监视DOM树的变化。它可以观察DOM节点的增删改操作,并在变化发生时触发回调函数。然而,原生的MutationObserver API并不支持使用Promise来处理异步操作。
为了解决这个问题,Promise.MutationObserver通过封装MutationObserver对象并返回一个Promise对象来处理异步操作。它可以将MutationObserver的回调函数包装成Promise的resolve或reject函数,从而能够使用Promise的链式调用和错误处理机制。
使用Promise.MutationObserver可以实现以下功能:
以一个例子来说明Promise.MutationObserver的使用:
const observer = new Promise.MutationObserver(callback);
observer.observe(document.body, {
subtree: true,
childList: true,
});
observer.then(() => {
console.log('DOM树发生了变化');
})
.catch((error) => {
console.error(error);
});
function callback(mutations, observer) {
// 异步操作
setTimeout(() => {
console.log('异步操作完成');
observer.takeRecords(); // 清空记录
observer.disconnect(); // 停止观察
observer.resolve(); // 触发Promise的resolve函数
}, 1000);
}
在上面的例子中,我们创建了一个Promise.MutationObserver对象,并传入一个回调函数。然后通过调用observe方法开始观察DOM树的变化。
当DOM树发生变化时,回调函数会执行一系列的异步操作,最后调用resolve函数来触发Promise对象的resolve。我们可以通过then方法来监听resolve的触发,并执行相应的操作。
如果在异步操作过程中发生了错误,可以通过catch方法来捕获错误并进行处理。
总之,Promise.MutationObserver是一个方便而强大的工具,可以简化DOM树变化的处理,并且提供了Promise的链式调用和错误处理机制。
Promise.resolve().then()是Promise对象的一个方法链,用于处理异步操作的结果。
Promise.resolve()是一个静态方法,它返回一个已经被解决(resolved)的Promise对象。它可以接受一个值作为参数,并将这个值封装成一个已经解决的Promise对象返回。如果参数本身就是一个Promise对象,则直接返回该Promise对象。
.then()方法是Promise对象的方法,用于添加回调函数来处理Promise对象的解决结果。它接受两个参数:一个是解决的回调函数,一个是拒绝的回调函数。在Promise对象解决后,会调用对应的回调函数来处理解决的值。
结合起来,Promise.resolve().then()的作用可以总结为:
通过这个方法链,我们可以进行一系列的异步操作,并在每个异步操作完成后,使用.then()方法链式地处理结果。这样的代码结构更加简洁,易于理解和维护。
下面是一个简单的例子来说明Promise.resolve().then()的使用:
Promise.resolve(42)
.then((value) => {
console.log(value); // 42
return value + 1;
})
.then((value) => {
console.log(value); // 43
return Promise.reject('出错了');
})
.catch((error) => {
console.error(error); // 出错了
return Promise.resolve('处理错误');
})
.then((value) => {
console.log(value); // 处理错误
});
在上面的例子中,我们首先使用Promise.resolve()创建了一个已经解决的Promise对象,并传入值42。
然后通过.then()方法添加了第一个回调函数,打印出了解决的值42,并返回了value + 1。
接下来,在第二个.then()方法里,我们返回了一个被拒绝的Promise对象,并在.catch()方法里捕获了错误,并打印出了错误信息"出错了"。
接着,我们又通过.then()方法添加了一个回调函数,并返回了一个已经解决的Promise对象,并且打印出了返回的值"处理错误"。
通过这个例子,我们可以看到,使用Promise.resolve().then()方法可以方便地处理多个异步操作的结果,并且可以在每个.then()方法里进行相应的处理和错误处理。
总之,Promise.resolve().then()是Promise对象的方法链,用于处理异步操作的结果,它简化了异步操作的处理和错误处理。
js阻碍渲染案例
启动函数前
在上述代码中,页面会卡住3秒后再进行重新渲染,死循环函数会占用渲染主线程3秒,这段时间内,如h1的更改操作,滚动页面等都会进入等待,在事件队列中排队。