pc做网站服务器,营销型网站和普通网站,绍兴网站制作方案,资讯门户 wordpress浏览器运行过程中会同时面对多种任务#xff0c;用户交互事件(鼠标、键盘)、网络请求、页面渲染等。而这些任务不能是无序的#xff0c;必须有个先来后到#xff0c;浏览器内部需要一套预定的逻辑来有序处理这些任务#xff0c;因此浏览器事件循环诞生了#xff0c;再次强…浏览器运行过程中会同时面对多种任务用户交互事件(鼠标、键盘)、网络请求、页面渲染等。而这些任务不能是无序的必须有个先来后到浏览器内部需要一套预定的逻辑来有序处理这些任务因此浏览器事件循环诞生了再次强调是浏览器事件循环不是javascript事件循环js只是浏览器事件循环的参与者。二、事件循环是什么浏览器把任务区分成了 宏任务 和 微任务 或者叫 外部任务 和 内部任务 内部任务可以理解为js内部处理的任务外部任务可以认为是浏览器处理的任务。外部队列/宏任务队列(Task Queue)也可以叫宏任务队列浏览器中的外部事件源包含以下几种dom操作(页面渲染)用户交互(鼠标、键盘)网络请求(Ajax等)History API操作(history.back、history.go...)定时器(setTimeout)这些外部事件源可能很多为了方便浏览器厂商优化HTML标准中明确指出一个事件循环有一个或多个外部队列而每一个外部事件源都有一个对应的外部队列。不同的时间源之间可以有不同的优先级(例如在网络时间和用户交互之间浏览器可以优先处理鼠标行为从而让用户感觉更加流畅)。内部队列/微任务队列(Microtask Queue)也可以叫微任务队列指的就是javascript语言内部的事件队列在HTML标准中并没有明确规定这个队列的事件源通常认为有以下几种Promise的成功(.then)与失败(.catch)MutationObserverObject.observe(已废弃)以上三种除了第一个其他两个可以认为没有实际上我们js中能够使用的就只有promise。事件循环模型先来一张事件循环处理模型的截图可以看出每一个事件循环从外部任务队列中拿出一个来执行执行完一个外部任务后立即执行内部任务队列中所有内部任务(清空)然后浏览器执行一次渲染然后再次循环。一段经典代码了解了两种队列和事件循环的执行模型下面来一段经典代码// 以下代码会得到什么样的输出结果console.log(1);setTimeout(function() { console.log(2); Promise.resolve().then(function() {console.log(3); });}, 0);Promise.resolve().then(function() { console.log(4);}).then(function() { console.log(5);});console.log(6);答案是164523执行顺序如下由于执行当前js代码这个任务是一个宏任务因此首先输出的是1继续执行遇到setTimeou由于setTimeout是一个外部事件源它内部的代码会被push到TaskQueue中等待下一次事件循环再执行当执行到promise的 then 或 catchd的时候会将他们按顺序追加到本轮事件循环的末尾再继续往下执行输出6宏任务完成后清空微任务队列中的任务继而输出4、5如果有的话执行渲染任务后本次事件循环结束开始执行下一个宏任务也就是第一个setTimeout中的代码块输出2然后将promise.then添加到本轮循环末尾清空微任务输出3三、浏览器与Node.js的事件循环差异区别对比对于两者的区别来张瞟来的截图这个例子的代码如下setTimeout((){ console.log(1); Promise.resolve().then(function() {console.log(2); });});setTimeout((){ console.log(3); Promise.resolve().then(function() {console.log(4); });});这段代码在浏览器和nodejs中的输出结果分别是什么呢通过前面对浏览事件循环的了解你应该很容易得出在浏览器中的输出结果是: 1234那在nodejs中的输出结果是什么呢结果是在nodejs的 v11.x 之前输出1324。这之间的原因是浏览器有非常多的用户交互事件为了用户体验更加流畅必须均匀的处理宏任务和微任务而在nodejs中由于并没有用户交互事件为了保证异步事件能够被均等的执行因此设计的初衷就是先清空宏任务队列再清空微任务队列。不过你应该注意到我上面只说了在 nodejs的 v11.x 之前输出1324但是nodejs这个特性在社区经历了一波开发者的吐槽之后node官方在 v11 这个版本紧急修复了这个问题。所以在 v11.x 以上版本执行以上代码会得到在浏览器中一样的结果。setImmediate先来张瞟来的截图我们再来一个例子setTimeout((){console.log(1);Promise.resolve().then(() console.log(2));});setTimeout((){ console.log(3); Promise.resolve().then(() console.log(4));});setImmediate(() {console.log(5); Promise.resolve().then(() console.log(6));});setImmediate(() {console.log(7); Promise.resolve().then(() console.log(8));});以上代码在nodejsV13.x中的执行结果是12345678接下来我们把顺序调换一下,在第二个位置插入setImmediatesetTimeout((){console.log(1);Promise.resolve().then(() console.log(2));});setImmediate(() {console.log(3); Promise.resolve().then(() console.log(4));});setTimeout((){ console.log(5); Promise.resolve().then(() console.log(6));});setImmediate(() {console.log(7); Promise.resolve().then(() console.log(8));});执行结果有一定的概率是12347856也有一定的概率是 12563478为啥不同的顺序会得到不同的结果呢这是由于setTImeout的精度问题导致的到了这个级别的时间精度代码执行的时间可能都会导致结果的不同。下面这张截图是nodejs官方文档对于事件循环顺序的展示其中timers阶段是用于执行setTimeout事件的check阶段是用于执行setImmediate事件的。Nodejs官方这个所谓事件循环过程其实只是完整的事件循环中Node.js的多个外部队列相互之间的优先级。setTimeout是由event loop检测系统时间是否到点然后向时间队列插入一个事件然后调用事件的回调方法。而setImmediate是监控UI线程的调用栈一旦调用栈为空则将回调压栈。讲了这么多其实对于上面setTimeout和setImmediate的对比结果还是有点模糊推测对于setImmediate的延时有时比setTimeout的要长由于setImmediate要先监控调用栈若调用栈为空才压栈那么在压栈之前event loop已经将setTimeout事件的回调函数压栈了。好了以上是这次分享的所有内容对于后面setTimeout和setImmedate的对比没有的出一个明确的结果有兴趣的可以一起讨论。