浏览器渲染,进程与线程

浏览器渲染

浏览器渲染:HTML解释器将从网络或本地获取的字节流转换成dom树;

1、Bytes字节流——Characters字符流——Tokens词语——Nodes节点——Dom树;

2、渲染Dom树,解析html下的标签如meta、link、script,渲染Dom节点。

字节流先解码成字符流,然后通过各种词法分析器(HTMLTokenizer,XSSAuditor)解析成词语,再通过语法分析器(HTMLDocumentParser,HTMLTreeBuilder)解析成节点,最后节点(HTMLConstructionSite)组建成dom树。

进程与线程

进程:指的是系统正在运行的1个程序。

浏览器打开1个页面就是打开1个进程,进程都是由系统资源分配的独立地址空间的实体

每个进程一般包含多个线程,同一个进程下的多个线程可以共享部分状态和读取同一块内存,每个线程拥有自己的寄存器和栈,其他线程可以访问这些栈内存。

线程:是进程的1个实体,就是去做具体事情的东西,一个线程只能专注做一件事情

当一个线程修改了进程中的资源,它的兄弟线程可立即看到这种变化。

进程与线程的区别:

1、地址空间:进程地址空间相互独立,同一进程下的线程空间共享。网页A进程下的线程(如网页A打开文件)在网页B进程内不可见。

2、通信:进程之间通信需要(管道、消息队列、共享内存、套接字),同一进程下线程可以直接读写数据来进行通信。

浏览器可开辟多个进程与多个线程

浏览器从关闭到启动,然后新开一个页面至少需要:1个浏览器进程,1个GPU进程,1个网络进程,和1个渲染进程,一共4个进程

Chrome浏览器包括:1个浏览器主进程1个GPU进程1个网络进程多个渲染进程,和多个插件进程

浏览器进程: 控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等,以及负责与其他进程的协调工作,同时提供存储功能

GPU进程:负责整个浏览器界面的渲染。Chrome刚开始发布的时候是没有GPU进程的,而使用GPU的初衷是为了实现3D CSS效果,只是后面网页、Chrome的UI界面都用GPU来绘制,这使GPU成为浏览器普遍的需求,最后Chrome在多进程架构上也引入了GPU进程

网络进程:负责发起和接受网络请求,以前是作为模块运行在浏览器进程里面的,后面才独立出来,成为一个单独的进程

插件进程:主要是负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响

渲染进程:负责控制显示tab标签页内的所有内容,核心任务是将HTML、CSS、JS转为用户可以与之交互的网页,排版引擎 Blink 和 JS 引擎 V8 都是运行在该进程中,默认情况下Chrome会为每个Tab标签页创建一个渲染进程

浏览器呈现出页面过程中,大部分工作都是在渲染进程中完成。

渲染进程中的线程:

GUI渲染线程:负责渲染页面,解析html和CSS、构建DOM树、CSSOM树、渲染树、和绘制页面,重绘重排也是在该线程执行。在Javascript引擎运行脚本期间,GUI渲染线程都是处于挂起状态的,GUI更新会被保存在一个队列中等到引擎线程空闲时立即被执行

JS引擎线程:一个页面只有一个JS引擎(单线程),负责解析和执行js,处理用户交互,操作DOM树和CSS样式树。

 HTTP线程:如果请求有回调函数,则把回调函数添加到事件队列,排队等待JS引擎处理

定时器线程:因为JS引擎是单线程,如果阻塞定时器线程就不准确了,所以浏览器开辟了单独的线程来负责定时器线程。

DOM线程:主要用来控制事件循环,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,排队等待JS引擎处理

        JS是采用事件驱动(event-driven)机制,来响应用户操作的,也就是单线程异步编程,JS是事件队列(EventQueue)+ 事件轮循(EventLoop)机制来完成单线程异步编程。

        当处理一些不能立即执行的函数或者其他的代码时,会将对应的任务在其可以触发的时机,添加到事件队列的末端(比如:定时任务、鼠标点击、AJAX异步请求等)

        事件循环机制会在JS引擎线程空闲时,循环访问事件队列的头部,如果有函数,则会将该函数推到执行栈中并立即执行

  

浏览器渲染页面

        遇到style内嵌样式,GUI直接渲染

                如果css代码量比较少,直接内嵌即可,拉取html的时候css也在里面,会直接渲染;

                如果css代码量比较多,如果还是要内嵌,会影响拉取html的速度,渲染会比较慢,此时就应该是要link外部样式

        遇到link,浏览器开启http线程去请求资源,同时GUI继续向下执行(异步)。GUI渲染完后等link加载完会再次执行GUI渲染页面。

                浏览器同时能发送的http请求是有数量限制的。(谷歌:5~7个);

                超过最大请求数的会排队,等待前面请求完成再请求。

                http请求数量越少越好

        遇到@import,浏览器开启http线程去请求资源,同时GUI暂停了(导入样式会阻碍GUI渲染),当资源请求回来后,GUI才继续渲染(同步)。

        真实项目应该慎用@import

        遇到<script src='xxx'></script>会阻碍GUI渲染(同步)。

                加defer:请求是异步的,和link一样,不会阻碍GUI渲染,GUI渲染完后等defer加载完后才会去渲染js。不同的script文件可以建立依赖关系,GUI渲染完成后会等待所有的加defer文件请求完成后,按照编写顺序执行这个defer文件。

                加async:请求是异步的会单独开启http请求,此时GUI继续渲染,等async请求回来后,GUI渲染会暂停,会去渲染js。

                        加async请求的不同文件之间不能有依赖关系,因为加async文件是谁先请求回来谁先执行。

        项目优化点:

                把link文件放在头部,在页面还没开始渲染就开启http去请求文件,dom渲染完,css也基本请求回来,更有效利用时间,提升页面渲染速度;把script放在底部,防止阻塞GUI渲染,如果不放在底部,就需要给script加async或defer。

预加载:谷歌浏览器的预加载扫描器会预先扫描html里面的src和link标签,在dom加载就开启http请求。但是GUI渲染的时候头部遇到script还是会被阻塞,会先渲染js然后才会继续GUI渲染。

webpack4.6.0已经实现了对预拉取和预加载的支持

import(/* webpackPreload: true */ 'xxx');   预加载, 浏览器会优先获取该资源

import(/* webpackPrefetch: true */  'xxx');  预拉取, 浏览器会等空闲时获取该资源

import(/* webpackChunkName: "lodash" */ /* webpackPrefetch: true */ 'lodash');

webpackChunkName 是为预加载的文件取别名

webpackPreload 会在父 chunk 加载时并行下载文件

webpackPrefetch 会在浏览器闲置下载文件

DOM TREE(当dom树创建完成会触发DOMContentLoaded事件,在这里可能会渲染js)  =>  CSSOM TREE  =>  RENDER-TREE渲染树(浏览器未来会按照这个结构来绘制dom树) => Layout布局计算(回流/重排) => Painting绘制(重绘).

        页面第一次加载一定会触发回流和重绘

        如果改变了元素的大小和位置,浏览器需要重新计算,就会触发回流,一旦发生回流必定触发重绘(回流很消耗性能: dom操作消耗性能90%说的都是dom回流. vue和react之所以性能更高,是因为它的虚拟dom变成真实dom的过程避免多次操作dom,它会整合很多改动集中做dom渲染 )

        如果改变了元素的普通样式改变,位置和大小不变,只需要重绘即可.

减少和避免回流

        放弃传统dom操作,使用vue和react框架操作视图

        读写分离,设置和读取样式分开操作,避免渲染队列刷新导致多次回流。https://blog.csdn.net/qq_27483091/article/details/120252230(轮播图应用读写分离使渲染队列立即执行)

        缓存布局:div.style.left = div.style.left + 10 +'px';

                        div.style.width =div.style.width+ 100 +'px';

                改为 var left = div.style.left,width = div.style.width ;

                        div.style.left = left + 10 +'px';  div.style.width= width + 100 +'px';

        元素批量修改:

                使用文档碎片 createDocumentFragment

                模板字符串拼接

       集中改变样式(老版浏览器): element.style.cssText ='width:50px;height:20;';  尽量写一起

       动画效果应该应用在position为absolute或fixed,脱离文档流,分层渲染

       使用css3硬件加速(属于开启GPU进程做单独加速处理):不会引起回流和重绘,transform、opacty、filters

        

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值