NODE - 前置知识(浏览器工作原理)

浏览器的功能及实现:

//浏览器的主要功能
渲染HTML和CSS、解析执行JS、人机交互(UI)、网络请求(Socket)、数据存储(cookie、localStorage、SessionStorage)。

//区分进程和线程
进程:CPU资源分配的最小单位,CPU会为每个进程分配独立的内存空间。
线程:CPU调度的最小单位。
线程基于进程:一个进程中可以有多个线程,同一个进程间的多线程之间共享资源。我们平常说的“单线程”和“多线程”,指的是一个进程中的“单”和“多”。

//浏览器是多进程的 - 合作共赢
Brower进程 - 主控协调,每个浏览器一个。
GPU进程 - 3D绘制,每个浏览器一个。
Render进程 - 浏览器内核,每个Tab一个。
浏览器为什么设计成多进程的:用空间换时间,避免其中某项崩溃影响他人。

 

展开讲讲Render进程:

//Render进程(浏览器内核)的组成
渲染大佬:
GUI渲染线程 - 解析HTML和CSS,完成布局和绘制,repaint和reflow。
JS四子:
JS引擎线程(如,V8引擎) - 解析JS脚本,执行代码,等待消息队列的任务并处理。
定时器触发线程 - setTimeout和setInterval所在的线程。
异步HTTP请求线程 - AJAX请求所在的线程。
事件触发线程 - 控制事件循环,在JS引擎空置时,将消息队列中的事件推给它。

//主流浏览器内核
Chrome:Blink引擎(是Webkit的一个分支)。
Safari:Webkit引擎(2012年停止开发Windows版Safari)。
Firefox:Gecko引擎。
Opera:Blink引擎(早期使用Presto引擎)。
IE:Trident引擎(IE11后改成Micorsoft Edge)。
Microsoft Edge:EdgeHTML引擎(是Trident的一个分支)。

 

展开讲讲GUI线程:

//先说说文件引入位置
CSS文件的下载会阻塞 Render Tree 的生成。
JS线程和GUI线程互斥,其中一个执行,另一个就要挂起。
<link css> 放在 <head> 里,优先加载 css文件,防止其阻塞 Render Tree 生成。
<script js> 放在 </body> 前,最后加载 js文件,防止其影响GUI的绘制。

//Reflow/Layout的性能问题
经典面试题:要求点击一个按钮,创建50个文本框,并加到按钮下面的DIV中,你会怎么做?
题目意图:要知道,每次向页面添加DOM节点,都会引发页面的Reflow/Layout,这个过程非常耗时。
正确做法:将创建好的节点加到 DocumentFragment里,而不是每次创建后都直接追加到页面中。
注意:Reflow和Layout其实是同一个意思,只不过在不同的引擎当中,他们的叫法不一样。

//补充 - DocumentFragment接口
DocumentFragment(文档片段)表示一个没有父级文件的最小文档对象:
它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。
它不是真实DOM树的一部分,它的变化不会引起DOM树的重新渲染的操作(reflow) ,所以不会引发性能问题。
用法:
常使用DocumentFragment作为参数,进行appendChild或insertBefore等操作。
创建:通多document.createDocumentFragment()方法或DocumentFragment()构造函数可以创建空的DocumentFragment。
属性:继承Node的所有属性,和ParentNode的部分属性(childrem、firstElementChild、lastElementChild、childElementCount)。
方法:继承Node的全部方法,并实现ParentNode接口中的方法
DocumentFragment.find() - 返回DocumentFragment树里的第一个匹配的元素Element。
DocumentFragment.findAll() - 返回DocumentFragment树里的所有匹配的元素NodeList。
DocumentFragment.querySelector() - 返回DocumentFragment树里的第一个匹配某选择器的元素Element。
DocumentFragment.querySelectorAll() - 返回DocumentFragment树里的所有匹配某选择器的元素NodeList。
DocumentFragment.getElementById() - 返回DocumentFragment树里的第一个匹配某ID的元素Element。
兼容性:
基本用法:所有浏览器都支持。
querySelector()、querySelectorAll():Chrome、FF3.5+、IE8+、Opera10+、Safari3.2+。
DocumentFragment()构造方法、find()、findAll()、ParentNode的属性和方法:支持度不高,还是别用了。

 

展开讲讲JS四子(浏览器中的事件循环):

//浏览器中事件循环 - 四个线程的击鼓传花
JS引擎线程:执行同步任务,形成一个执行栈。
定时器触发线程、异步HTTP请求线程:执行异步任务。
事件触发线程:管理着一个任务队列,异步任务有了运行结果,就在任务队列中放置一个事件。
JS引擎线程空闲时(干完活):就去读任务队列,将队列中可以执行的任务加入执行栈。

//异步任务的来历
异步任务来自AJAX的回调事件、定时器中包裹的待执行事件等。
JS引擎是单线程的,处于阻塞状态会影响计时,所以单开了定时器触发线程。

//macrotask与microtask
macrotask(宏任务,task):每次执行栈执行的代码就是一个宏任务。
microtask(微任务,job):在task执行完后,立即执行的代码就是一个微任务。
这个概念诞生于 ES6 的 Promise:
宏任务 - 主代码块、setTimeout回调、setInterval回调、AJAX回调。
微任务 - Promise.process.nextTick等。
执行时机:task→job→渲染→task→job→渲染……
浏览器为了使task和dom任务有序执行,规定要在两次task间重新渲染页面。
job会在task后马上执行,所以有了上面的执行时机,这期间穿插了JS线程和UI线程的切换。
延伸:可以通过WebWorker实现浏览器中的多线程。

 

posted @ 2018-11-05 13:16  月亮和电池  阅读(424)  评论(0编辑  收藏  举报