浏览器的主要组成组件
谈javascript运行机制,我们先从它的宿主环境浏览器组成部分说起,包含如下几个组成部分
1. 用户界面(User Interface) - 包括地址栏、前进/后退按钮、书签菜单等
2. 浏览器引擎(Browser engine) - 在用户界面和呈现引擎之间传送指令。
3. 呈现引擎(Rendering engine) - 负责显示请求的内容。
4. 网络(Networking) - 用于网络调用。
5. 用户界面后端(UI Backend) - 用于绘制基本的窗口小部件,比如组合框和窗口。
6. JavaScript 解释器(JavaScript Interpreter)。用于解析和执行 JavaScript 代码。
7. 数据存储(Data Persistence)。这是持久层。浏览器需要在硬盘上保存各种数据。
作为一名前端开发工程师,我们着重了解的是呈现引擎以及javascript解释器
呈现引擎
呈现引擎,又称渲染引擎,也被称为浏览器内核,在线程方面又称为 UI 线程,负责dom的渲染。
javascript解释器
JavaScript 解释器就是能够“读懂” JavaScript代码,并给出正确运行结果,也就是我们口中的javscript引擎。
呈现引擎和javascript解释器关系
由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。所以,浏览器设置 UI 渲染线程与 JavaScript 引擎线程为互斥的关系,也就是说,当 JavaScript 引擎线程执行时 UI 渲染线程会被挂起,UI 更新会被保存在一个队列中等到 JavaScript 引擎线程空闲时立即被执行。
页面卡顿的真正原因
假设一个 JavaScript 代码执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染出现“加载阻塞”的现象。当然,针对 DOM 的大量操作也会造成页面出现卡顿现象。
优化方案
1. 减少 JavaScript 加载对 DOM 渲染的影响(将 JavaScript 代码的加载逻辑放在 HTML 文件的尾部,减少对渲染引擎呈现工作的影响);
2. 避免重排,减少重绘(避免白屏,或者交互过程中的卡顿);
3. 减少 DOM 的层级(可以减少渲染引擎工作过程中的计算量);
4. 使用 requestAnimationFrame 来实现视觉变化(一般来说我们会使用 setTimeout 或 setInterval 来执行动画之类的视觉变化,但这种做法的问题是,回调将在帧中的某个时点运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿);
js执行机制
javascript为什么是单线程
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?。
什么是eventloop
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。但是很多时候cpu是闲的,主要是一些io设备比较慢(如ajax从网络读取数据),JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去,这就是eventloop。
详解eventloop
javascript所有任务分为同步任务和异步任务,同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
同时异步任务又分为,正常任务(task)与微任务(microtask)。它们的区别在于,“正常任务”在下一轮Event Loop执行,“微任务”在本轮Event Loop的所有任务结束后执行。
正常任务: setTimeout setInterval setImmediate I/O 各种事件(比如鼠标单击事件)的回调函数
微任务: 微任务目前主要是process.nextTick和 Promise 这两种情况。
网友评论