宜宾网站建设,wordpress底部音乐插件,搜索引擎优化策略有哪些,企业所得税减免政策2023一、浏览器的进程模型
浏览器是一个多进程多线程的应用程序#xff0c;浏览器内部工件极其复杂#xff0c;为了减少连环崩溃的几率#xff0c;当启动浏览器后#xff0c;它会自动启动多个进程#xff0c;其中#xff0c;有以下主要进程#xff1a;
1.浏览器进程
浏览…一、浏览器的进程模型
浏览器是一个多进程多线程的应用程序浏览器内部工件极其复杂为了减少连环崩溃的几率当启动浏览器后它会自动启动多个进程其中有以下主要进程
1.浏览器进程
浏览器主要负责界面显示、用户交互、子进程管理等浏览器进程内部会启动多个线程处理不同的任务。
2.网络进程
网络进程主要加载网络资源也会启动多线程。
3.渲染进程
渲染进程启动后会开启一个渲染主线程主线程负责执行HTML、CSS、JS代码在默认情况下浏览器会为每个标签开启一个新的渲染进程以保证不同的标签页之间不相互影响。
二、渲染主线程的工作
渲染主线程是浏览器中最繁忙的线程它要处理的任务包括但不限于
解析HTML解析CSS计算样式进行布局处理图层连续渲染画面FPS帧率如每秒把页面画60次执行全局JS代码执行事件处理函数执行计时器的回调函数等
渲染主线程的任务调度方式是排队浏览器的任务会进入消息队列事件队列
三、事件队列消息队列
在最开始的时候渲染主线程会进入一个无线循环每一次循环会检查事件队列中是否有任务存在如果有就取出队头的任务执行第一个任务执行完一个后进入下一次循环如果没有则进入休眠状态。其他所有的线程包括其他进程的线程可以随时向事件队列添加任务新任务会加到事件队列的队尾。在添加新任务时如果主线程是休眠状态则会将其唤醒来继续循环拿取任务。
四、浏览器的异步机制
在代码执行过程中会遇到一些无法立即处理的任务。例如
计时完成后需要执行的任务——setTimeout、setInterval网络通信完成后需要执行的任务——XHR、Fetch用户操作后需要执行的任务——addEventListener
如果让渲染主线程等待这些任务的时机达到就会导致主线程长期处于阻塞的状态从而导致浏览器卡死。这是浏览器就会使用异步来解决这个问题。
具体操作
异步的具体做法是当某些任务发生时比如计时器、网络、事件监听这是主线程将任务交给其他线程去处理自身立即结束任务的执行转而执行后续代码。当其他线程完成时将事先传递的回调函数包装成任务加入到事件队列的队尾排队等待主线程调度执行。
五、事件队列的优先级
任务没有优先级但事件队列有优先级
在过去的浏览器中有一个宏队列和一个微队列VIP而现在的浏览器中每个任务都有一个任务类型同一个类型的任务必须在一个队列中不同类型的任务可以分属于不同的队列在一次事件循环中浏览器可以根据实际情况从不同的队列中取出任务执行w3c规定浏览器必须准备好一个微队列micro task queue微队列中的任务优先所有其他任务执行。
chrome中的队列优先级
在目前chrome中有延时队列中、交互队列高、微队列最高等添加到微队列的主要方式是 Promise.MutationObserver 例如
Promise.resolve().then(函数) //立即把一个函数加入微队列
这里对上述两个方法进行一定的解释
Promise.MutationObserver
Promise.MutationObserver是一个基于Promise对象的封装实现用于将MutationObserver和Promise结合起来处理DOM树的变化。
MutationObserver是浏览器提供的一个API用于监视DOM树的变化。它可以观察DOM节点的增删改操作并在变化发生时触发回调函数。然而原生的MutationObserver API并不支持使用Promise来处理异步操作。
为了解决这个问题Promise.MutationObserver通过封装MutationObserver对象并返回一个Promise对象来处理异步操作。它可以将MutationObserver的回调函数包装成Promise的resolve或reject函数从而能够使用Promise的链式调用和错误处理机制。
使用Promise.MutationObserver可以实现以下功能
监视DOM树的变化并在变化发生后执行一系列的异步操作。可以通过链式调用的方式依次执行一系列的异步操作并在最后返回一个Promise对象。可以通过catch方法捕获错误并进行相应的错误处理。
以一个例子来说明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.resolve().then()是Promise对象的一个方法链用于处理异步操作的结果。
Promise.resolve()是一个静态方法它返回一个已经被解决resolved的Promise对象。它可以接受一个值作为参数并将这个值封装成一个已经解决的Promise对象返回。如果参数本身就是一个Promise对象则直接返回该Promise对象。
.then()方法是Promise对象的方法用于添加回调函数来处理Promise对象的解决结果。它接受两个参数一个是解决的回调函数一个是拒绝的回调函数。在Promise对象解决后会调用对应的回调函数来处理解决的值。
结合起来Promise.resolve().then()的作用可以总结为
创建一个已经解决的Promise对象添加回调函数来处理解决的结果。
通过这个方法链我们可以进行一系列的异步操作并在每个异步操作完成后使用.then()方法链式地处理结果。这样的代码结构更加简洁易于理解和维护。
下面是一个简单的例子来说明Promise.resolve().then()的使用
Promise.resolve(42).then((value) {console.log(value); // 42return value 1;}).then((value) {console.log(value); // 43return 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的相关案例及知识
1.JS阻塞渲染
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titlejs阻碍渲染案例/title
/head
bodybutton点击我启动函数/buttondivh1启动函数前/h1/div
/body
scriptlet btn document.querySelector(button);let h1 document.querySelector(h1);btn.addEventListener(click,function(){h1.textContent 我是函数启动后;function abc(){let start Date.now();while(Date.now()-start3000);};abc();});
/script
/html
在上述代码中页面会卡住3秒后再进行重新渲染死循环函数会占用渲染主线程3秒这段时间内如h1的更改操作滚动页面等都会进入等待在事件队列中排队。
2.JS中的计时器不能精准计时的原因
计算机硬件误差计算机内没有原子钟该方法调用的是操作系统的计时函数但操作系统的计时函数本身误差w3c中规定如果嵌套层超过5层则会带有4毫秒的最少时间受事件循环的影响计时器的回调函数只能在主线程空闲时运行
七、总结
单线程是异步产生的原因事件循环是异步的实现方式