标签:load 配置 tar 哪些 使用 The static loop return
对于单线程来说,事件循环可以说是重中之重了,它为任务分配不同的优先级,井然有序的调度。让js解析,用户交互,页面渲染等互不冲突,各司其职。
我们书写的代码无时无刻都在和事件循环打交道,要想写出更流畅,我们就必须深入了解事件循环,下面我们将从规范中翻译和解读整个流程。
以下内容来自whatwg文档,均为个人理解,若有不对,烦请指出,我会第一时间修改,避免误导他人!
为了协调用户操作,js执行,页面渲染,网络请求等事件,每个宿主中,存在事件循环这样的角色,并且该角色在当前宿主中是唯一的。
简单解释一下宿主:宿主是一个ECMAScript执行上下文,一般包含执行上下文栈,运行时执行环境,宿主记录和一个执行线程,除了这个执行线程外,其他的专属于当前宿主。例如,某些浏览器在不同的tabs使用同一个执行线程。
不仅如此,事件循环又存于在各个不同场景,有浏览器环境下的,worker环境下的和Worklet环境下的。
Worklet是一个轻量级的web worker,可以让开发者访问更底层的渲染工作线,也就是说你可以通过Worklet去干预浏览器的渲染环境。
提到了worklet,那就顺便看一个例子(需开启服务,不要以file协议运行),通过这个例子,可以看到事件循环不同阶段触发了什么钩子函数:
<!DOCTYPE html><html lang=‘en‘> <head> <meta charset=‘UTF-8‘ /> <meta name=‘viewport‘ content=‘width=device-width, initial-scale=1.0‘ /> <title>Document</title> <style> .fancy { background-image: paint(headerHighlight); display: layout(sample-layout); background-color: green; } </style> </head> <body> <h1 class=‘fancy‘>My Cool Header</h1> <script> console.log(‘开始‘); CSS.paintWorklet.addModule(‘./paint.js‘); CSS.layoutWorklet.addModule(‘./layout.js‘); requestAnimationFrame(() => { console.log(‘requestAnimationFrame‘); }); Promise.resolve().then(() => { console.log(‘微任务‘); }); setTimeout(function () { document.querySelector(‘.fancy‘).style.height = ‘150px‘; (‘translateZ(0)‘); Promise.resolve().then(() => { console.log(‘新一轮的微任务‘); }); requestAnimationFrame(() => { console.log(‘新一轮的requestAnimationFrame‘); }); }, 2000); console.log(2); </script> </body></html>
// paint.jsregisterPaint( ‘headerHighlight‘, class { static get contextOptions() { console.log(‘contextOptions‘); return {alpha: true}; } paint(ctx) { console.log(‘paint函数‘); } });// ==========================分割线// layout.jsregisterLayout( ‘sample-layout‘, class { async intrinsicSizes(children, edges, styleMap) {} async layout(children, edges, constraints, styleMap, breakToken) { console.log(‘layout阶段‘); } });
事件循环有一个或多个Task队列,每个Task队列都是Task的一个集合。其中Task不是指我们的某个函数,而是一个上下文环境,结构如下:
这里的Task队列不是Task,是一个集合,因为取出一个Task队列中的Task是选择一个可执行的Task,而不是出队操作。
微任务队列是一个入对出对的队列。
这里说明一下,Task队列为什么有多个,因为不同的Task队列有不同的优先级,进而进行次序排列和调用,有没有感觉react的fiber和这个有点类似?
举个例子,Task队列可以是专门负责鼠标和键盘事件的,并且赋予鼠标键盘队列较高的优先级,以便及时响应用户操作。另一个Task队列负责其他任务源。不过也不要饿死任何一个task,这个后续处理模型中会介绍。
Task封装了负责以下任务的算法:
事件循环有一个当前运行中的Task,可以为null,如果是null的话,代表着可以接受一个新的Task(新一轮的步骤)。
事件循环有微任务队列,默认为空,其中的任务由微任务排队算法创建。
事件循环有一个执行微任务检查点,默认为false,用来防止微任务死循环。
微任务检查算法:
event loop会按照下面这些步骤进行调度:
除此之外,还会在触发resize、scroll、建立媒体查询、运行css动画等,也就是说浏览器几乎大部分用户操作都发生在事件循环中,更具体点是事件循环中的ui render部分。之后会进行requestAnimationFrame和IntersectionObserver的触发,再之后是ui渲染
借鉴网上的一张图来粗略表示下整个流程
上面就是整个事件循环的流程,浏览器就是按照这个规则一遍遍的执行,而我们要做的就是了解并适应这个规则,让浏览器渲染出性能更高的页面。
比如:
最后感谢大家阅读,欢迎一起探讨!
标签:load 配置 tar 哪些 使用 The static loop return
原文地址:https://www.cnblogs.com/yangzhuxian/p/13371612.html