一、浏览器
什么是URL
组成部分:
protocol:协议,表明浏览器必须使用何种协议
domain:域名,表示正在请求哪个服务器
port:端口
path:网络服务器上资源的路径
parameters/query:提供给网络服务器的额外参数
anchor/fragment:资源本身的另一部分的锚点,锚点表示资源中的一种“书签”,给浏览器显示位于该“加书签”位置的内容的方向
scheme:// user:passwd@ host:port path ?query #fragment
scheme 表示协议名,比如http, https, file等等。后面必须和://连在一起。
user:passwd@ 表示登录主机时的用户信息,不过很不安全,不推荐使用,也不常用。
host:port表示主机名和端口。
path表示请求路径,标记资源所在位置。
query表示查询参数,为key=val这种形式,多个键值对之间用&隔开。
fragment表示 URI 所定位的资源内的一个锚点,浏览器可以根据这个锚点跳转到对应的位置。
https://www.baidu.com/s?wd=HTTP&rsv_spt=1 这个 URI 中,https即scheme部分,www.baidu.com为host:port部分,域名部分:端口号(注意,http 和 https 的默认端口分别为80、443),/s为path部分,而wd=HTTP&rsv_spt=1就是query部分。
什么是BOM,有哪些常用的BOM 对象及其属性?
location对象:用于获取或设置窗体的URL,并且可以用于解析URL
属性:hash\host\hostname…
其他方法:
location.search 返回参数
location.assign() 跳转页面,可以重定向页面
location.replace() 替换当前页面,但是没有历史记录,不可回退
location.reload()
history对象:记录用户曾经浏览过的页面(URL),并可以实现浏览器的前进与后退相似导航功能
属性:length 返回浏览器历史列表中的URL数量
方法:
back() 加载history列表中的前一个URL
forward() 加载history列表中的下一个URL
go() 加载history列表中的某个具体的页面
navigator对象:包含有关浏览器的信息,通常用于检测浏览器与操作系统的版本
appCodeName 浏览器代码名的字符串表示
appName 返回浏览器的名称
appVersion 返回浏览器的平台和版本信息
platform 返回运行浏览器的操作系统平台
userAgent 返回由客户端发送服务器的user-agent头部的值
CSRF和XSS攻击及防御手段
CSRF(跨站请求伪造)
攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的
本质:重要的操作参数都是可以被攻击者预测的,攻击者发出预测出URL的所有参数与参数值,成功伪造了一个请求
防御:使用验证码;检查HTTPS头部referer字段
Referer 首部包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。组成:协议+域名+端口号+路径+参数
通用方法:Token
使用Anti-CSRF Token 在URL中保持原参数不变,新增一个参数Token。Token的值是随机的(必须使用足够安全的随机数生成算法,或者采用真随机数生成器),其为用户与服务器所共同持有,可以放在用户的Session中,或者浏览器的Cookie中。 注意保密,尽量把Token放在表单中(构造一个隐藏的input元素),以POST提交,避免Token泄露。
XSS(跨站脚本攻击)
网站没有对用户的输入进行严格的限制, 使得攻击者可以将恶意js脚本上传到帖子让其他人浏览到有恶意脚本的页面
如何防范XSS:
在http头部配上set-cookie,其中
httponly:该属性会禁止JS脚本使用document.cookie来访问cookie
secure:该属性告诉浏览器仅在请求为HTTPS的时候才发送cookie
什么是中间人攻击?
此时⼜带来⼀个问题,MITM中间人攻击:攻击者相当于一个介入通信的传话员,攻击者知道通信双方的所有通信内容且可以任意增加、删除、修改双方的通信内容,而双方对此并不知情。
如果此时在客户端和服务器之间存在⼀个中间⼈,这个中间⼈只需要把原本双⽅通信互发的公钥,换成⾃⼰的公钥,这样中间⼈就可以轻松解密通信双⽅所发送的所有数据。
所以这个时候需要⼀个安全的第三⽅颁发证书CA,证明身份的身份,防⽌被中间⼈攻击。 证书中包括:签发者、证书⽤途、使⽤者公钥、使⽤者私钥、使⽤者的HASH算法、证书到期时间等。
但是问题来了,如果中间⼈篡改了证书,那么身份证明是不是就⽆效了?这个证明就⽩买了,这个时候需要⼀个新的技术,数字签名。
数字签名就是⽤CA⾃带的HASH算法对证书的内容进⾏HASH得到⼀个摘要,再⽤CA的私钥加密,最终组成数字签名。当别⼈把他的证书发过来的时候,我再⽤同样的Hash算法,再次⽣成消息摘要,然后⽤CA的公钥对数字签名解密,得到CA创建的消息摘要,两者⼀⽐,就知道中间有没有被⼈篡改了。这个时候就能最⼤程度保证通信的安全了。
6. 有哪些可能引起前端安全的问题?
7. 网络劫持有哪几种,如何防范?
二、进程与线程
进程与线程
什么是进程?
CPU是计算机的核心,承担所有的计算任务,官网说法,进程是CPU资源分配的最小单位,字面意思就是进行中的程序,我将它理解为一个可以独立运行且拥有自己的资源空间的任务程序。进程包括运行中的程序和程序所使用到的内存和系统资源。
什么是线程?
线程是CPU调度的最小单位,线程是建立在进程的基础上的一次程序运行单位,通俗点解释线程就是程序中的一个执行流,一个进程可以有多个线程。一个进程中只有一个执行流称作单线程,即程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。一个进程中有多个执行流称作多线程,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
进程与线程的区别
(1)进程是操作系统分配资源的最小单位,线程是程序执行的最小单位;
(2)一个进程由一个或多个线程组成,线程可以理解为是一个进程中代码的不同执行路线;
(3)进程之间相互独立,但同一进程下的各个线程间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号);
(4)调度和切换:线程上下文切换比进程上下文切换要快得多
多进程和多线程
多进程:多进程指的是在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态。多进程带来的好处是明显的,比如大家可以在网易云听歌的同时打开编辑器敲代码,编辑器和网易云的进程之间不会相互干扰
多线程:多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务
JS为什么单线程的
JS的单线程,与它的用途有关。
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准。有人说,js还有Worker线程,对的,为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程是完 全受主线程控制的,而且不得操作DOM。所以,这个标准并没有改变JavaScript是单线程的本质。
进程之间的通信方式
无名管道:半双工通信方式,数据只能单向流动且只能在有亲缘关系的进程间使用
有名管道:半双工通信方式,允许在非亲缘关系的进程间使用
信号:通知接收进程某个事件已发生
消息队列:传递消息的链表,存放在内核中。克服了信号传输信息少,管道只能传输无格式字节流以及缓冲区大小受限的缺点
信号量:一个计数器,用来控制多个进程对共享资源的访问。常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源
共享内存:映射一份能被其他进程所访问的内存,这份内存由一个进程创建但其他进程可以访问
套接字:不同机器之间的进程通信
进程的三种状态
就绪(Ready)状态
进程已分配到除CPU以外的所有必要资源,只要获得处理机便可立即执行。
执行(Running)状态
进程已获得处理机,其程序正在处理机上执行。
阻塞(Blocked)状态
正在执行的程序,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的原因可能是等待I/O完成、申请缓冲区不能满足、等待信号等。
什么是僵尸进程?
僵尸进程是已完成且处于终止状态,但在进程表中却仍然存在的进程。僵尸进程通常发生在父子关系的进程中,由于父进程仍需要读取其子进程的退出状态所造成的。
死锁产生的原因? 如果解决死锁的问题
死锁:
是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
系统中的资源分为两类:
可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;
不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。
产生死锁的原因:
(1)竞争资源:
(2)进程之间推进顺序非法:若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁。例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞
产生死锁的必要条件:
互斥条件:一个资源每次只能被一个进程使用
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
不剥夺条件:进程已获得的资源在未使用完之前不能强行剥夺
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
预防死锁的方法:
资源一次性分配:预先分配资源,即进程在运行前一次性地向系统申请它所需要的的全部资源。若某个进程所需的全部资源得不到满足则不分配任何资源,此进程暂不运行,直到系统能够满足当前进程的全部资源时才一次性将所申请的资源全部分配给该进程。(破坏请求条件)
资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)
可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
7. 如何实现浏览器内多个标签页之间的通信????
8. 对Service Worker的理解(缓存相关)????
浏览器包含哪些进程
(1)Browser进程:
浏览器的主进程,负责协调、主控,该进程只有一个;
负责浏览器界面显示,与用户进行交互。比如前进、后退;
负责各个页面的管理,创建和销毁其他进程;
将渲染进程得到的内存中的位图Bitmap,绘制到用户界面上;
网络资源的管理、下载;
(2)第三方插件进程:
每个类型的插件对应一个进程、当使用该插件的时候才创建;
(3)GPU进程:
该进程只有一个,用于3D绘制等;
(4)渲染进程:
就是通常所说的浏览器内核Renderer进程,内部是多线程;
每个Tab页面有一个渲染进程,互不影响;
主要进行页面的渲染、脚本执行、事件处理等;
渲染进程的常用线程
GUI渲染进程:
-负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等
解析html代码(HTML代码本质是字符串)转化为浏览器认识的节点,生成DOM树,也就是DOM Tree
解析css,生成CSSOM(CSS规则树)
把DOM Tree 和CSSOM结合,生成Rendering Tree(渲染树)
-当我们修改了一些元素的颜色或者背景色,页面就会重绘(Repaint)
-当我们修改元素的尺寸,页面就会重排(Reflow也叫回流)
-当页面需要Repaing和Reflow时GUI线程执行,绘制页面
-回流(Reflow)比重绘(Repaint)的成本要高,我们要尽量避免Reflow和Repaint
-GUI渲染线程与JS引擎线程是互斥的
当JS引擎执行时GUI线程会被挂起(相当于被冻结了)
GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行
JS引擎线程
-JS引擎线程就是JS内核,负责处理Javascript脚本程序(例如V8引擎)
-JS引擎线程负责解析Javascript脚本,运行代码
-JS引擎一直等待着任务队列中任务的到来,然后加以处理
浏览器同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的
一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
-GUI渲染线程与JS引擎线程是互斥的,js引擎线程会阻塞GUI渲染线程
就是我们常遇到的JS执行时间过长,造成页面的渲染不连贯,导致页面渲染加载阻塞(就是加载慢)
例如浏览器渲染的时候遇到
浏览器渲染流程
(1)解析 HTML 文件生成DOM 树
(2)解析 CSS 生成CSSOM规则树
(3)结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree),这一过程称为 Attachment
(3)遍历渲染树开始布局,计算每个节点的位置大小信息;
(4)将渲染树每个节点绘制到屏幕;
(5)浏览器主进程将默认的图层和复合图层交给 GPU 进程,GPU 进程再将各个图层合成(composite),最后显示出页面
什么是渲染层合并 (Composite) ?
渲染层合并,对于页面中 DOM 元素的绘制(Paint)是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将绘制的位图发送给 GPU 绘制到屏幕上,将所有层按照合理的顺序合并成一个图层,然后在屏幕上呈现。
三、浏览器缓存
http缓存的作用?
节省资源,节省流量,节省时间,也就是所谓的优化。
时间:
通常情况下通过网络获取内容速度慢成本高,有些响应需要在客户端和服务器之间进行多次往返通信,这就拖延了浏览器可以使用和处理内容的时间,同时也增加了访问者的数据成本。
资源:
通过缓存,使用资源副本,大大减少获取资源时间,
流量:
能够减少网络带宽消耗、减少延迟与网络阻塞,同时降低服务器压力,提高服务器性能。
HTTP缓存方式
两种缓存方式,根据响应的header内容来决定
强缓存(状态码:200):浏览器不向服务器发送任何请求,直接从本地缓存中读取文件并返回(相关字段:Cache-Control、Expires)
协商缓存(状态码304):浏览器发送请求到服务器,通过服务器来告知缓存是否可用(相关字段:Last-Modified/If-Modified-Since、Etag/If-None-Match)
强缓存
强缓存:使用强缓存策略时,如果缓存资源有效,则直接使用缓存资源,不必再向服务器发起请求。
Expires:服务器通过在响应头中添加 Expires 属性,来指定资源的过期时间。在过期时间以内,该资源可以被缓存使用,不必再向服务器发送请求。这个时间是一个绝对时间,它是服务器的时间,因此可能存在这样的问题,就是客户端的时间和服务器端的时间不一致,或者用户可以对客户端时间进行修改的情况,这样就可能会影响缓存命中的结果。Expires 是 http1.0 中的方式,因为它的一些缺点,在 HTTP 1.1 中提出了一个新的头部属性就是 Cache-Control 属性。
Cache-Control:
*max-age=xxx:缓存的内容将在 xxx 秒后失效,这个选项只在 HTTP1.1 可用,并如果和 Last-Modified 一起使用时,优先级较高。
*no-cache: 在浏览器使用缓存前,会往返对比 ETag,如果 ETag 没变,返回 304,则使用协商缓存。no-cache的目的就是为了防止从缓存中获取过期的资源。
*no-store: 彻底禁用缓存,所有内容都不会被缓存到缓存或临时文件中,每次都会向服务端发起新的请求,拉取最新的资源;
*public: 所有内容都将被缓存(客户端和代理服务器都可缓存)
*private: 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)
协商缓存
它是一种服务端的缓存策略,即通过服务端来判断某件事情是不是可以被缓存。
使用协商缓存策略时,服务端判断客户端的资源,是否和服务端资源一样,如果一致则返回 304 ,反之返回 200 和最新的资源。
在响应头部 Response Headers 中,有两种资源标识:
Last-Modified 资源的最后修改时间,对应请求头为 If-Modified-Since ;
Etag 资源的唯一标识,所谓唯一,可以想象成时人类的指纹,具有唯一性;但 Etag 的本质是一个字符串;对应请求头为 If-None-Match
Last-Modified 和 Etag
当响应头部 Response Headers 同时存在 Last-Modified 和 Etag 的值时,会优先使用 Etag ;
Last-Modified 只能精确到秒级;
如果资源被重复生成,而内容不变,则 Etag 更精确
https://juejin.cn/post/6974529351270268958#heading-18
浏览器缓存的全过程
浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时对比使用;
下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;
如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;
服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;
如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;
为什么需要浏览器缓存?
如果没有缓存的话,每一次网络请求都要加载大量的图片和资源,这会使页面的加载变慢许多。那缓存的目的其实就是为了尽量减少网络请求的体积和数量,让页面加载的更快。
使用浏览器缓存,有以下优点:
减少了服务器的负担,提高了网站的性能
加快了客户端网页的加载速度
减少了多余网络数据传输
哪些资源可以被缓存?——静态资源(js、css、img)
网站的 html 是不能被缓存的。因为网站在使用过程中 html 随时有可能被更新,随时有可能被替换模板。
网页的业务数据也是不能被缓存的。比如留言板和评论区,用户随时都可以在底下评论,那数据库的内容就会被频繁被更新
点击刷新按钮或者按 F5、按 Ctrl+F5 (强制刷新)、地址栏回车有什么区别?
点击刷新按钮或者按 F5:强制缓存失效,协商缓存有效
浏览器直接对本地的缓存文件过期,但是会带上If-Modifed-Since,If-None-Match,这就意味着服务器会对文件检查新鲜度,返回结果可能是 304,也有可能是 200
用户按 Ctrl+F5(强制刷新):强制缓存失效,协商缓存失效
浏览器不仅会对本地文件过期,而且不会带上 If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是 200
地址栏回车:强制缓存有效,协商缓存有效
浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查新鲜度,最后返回内容。
四、浏览器组成
对浏览器的理解
浏览器的主要功能是将用户选择的 web 资源呈现出来,它需要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式通常是 HTML,也包括 PDF、image 及其他格式。用户用 URI(Uniform Resource Identifier 统一资源标识符)来指定所请求资源的位置。
浏览器可以分为两部分,shell 和 内核。其中 shell 的种类相对比较多,内核则比较少。也有一些浏览器并不区分外壳和内核。从 Mozilla 将 Gecko 独立出来后,才有了外壳和内核的明确划分。
shell 是指浏览器的外壳:例如菜单,工具栏等。主要是提供给用户界面操作,参数设置等等。它是调用内核来实现各种功能的。
内核是浏览器的核心,内核是基于标记语言显示内容的程序或模块。
对浏览器内核的理解
浏览器内核主要分成两部分:
渲染引擎的职责就是渲染,即在浏览器窗口中显示所请求的内容。默认情况下,渲染引擎可以显示 html、xml 文档及图片,它也可以借助插件显示其他类型数据,例如使用 PDF 阅读器插件,可以显示 PDF 格式。
JS 引擎:解析和执行 javascript 来实现网页的动态效果。
最开始渲染引擎和 JS 引擎并没有区分的很明确,后来 JS 引擎越来越独立,内核就倾向于只指渲染引擎。
3. 常见的浏览器内核比较
常见浏览器所用内核
(1) IE 浏览器内核:Trident 内核,也是俗称的 IE 内核;
(2) Chrome 浏览器内核:统称为 Chromium 内核或 Chrome 内核,以前是 Webkit 内核,现在是 Blink内核;
(3) Firefox 浏览器内核:Gecko 内核,俗称 Firefox 内核;
(4) Safari 浏览器内核:Webkit 内核;
(5) Opera 浏览器内核:最初是自己的 Presto 内核,后来加入谷歌大军,从 Webkit 又到了 Blink 内核;
(6) 360浏览器、猎豹浏览器内核:IE + Chrome 双内核;
(7) 搜狗、遨游、QQ 浏览器内核:Trident(兼容模式)+ Webkit(高速模式);
(8) 百度浏览器、世界之窗内核:IE 内核;
浏览器的主要组成部分
⽤户界⾯ - 包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗⼝显示的您请求的⻚⾯外,其他显示的各个部分都属于⽤户界⾯。
浏览器引擎 - 在⽤户界⾯和呈现引擎之间传送指令。
呈现引擎 - 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
⽹络 - ⽤于⽹络调⽤,⽐如 HTTP 请求。其接⼝与平台⽆关,并为所有平台提供底层实现。
⽤户界⾯后端 - ⽤于绘制基本的窗⼝⼩部件,⽐如组合框和窗⼝。其公开了与平台⽆关的通⽤接⼝,⽽在底层使⽤操作系统的⽤户界⾯⽅法。
JavaScript 解释器。⽤于解析和执⾏ JavaScript 代码。
数据存储 - 这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“⽹络数据库”,这是⼀个完整(但是轻便)的浏览器内数据库。
五、浏览器渲染原理
浏览器包含哪些进程
(1)Browser进程:
浏览器的主进程,负责协调、主控,该进程只有一个;
负责浏览器界面显示,与用户进行交互。比如前进、后退;
负责各个页面的管理,创建和销毁其他进程;
将渲染进程得到的内存中的位图Bitmap,绘制到用户界面上;
网络资源的管理、下载;
(2)第三方插件进程:
每个类型的插件对应一个进程、当使用该插件的时候才创建;
(3)GPU进程:
该进程只有一个,用于3D绘制等;
(4)渲染进程:
就是通常所说的浏览器内核Renderer进程,内部是多线程;
每个Tab页面有一个渲染进程,互不影响;
主要进行页面的渲染、脚本执行、事件处理等;
渲染进程的常用线程
GUI渲染进程:
-负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等
解析html代码(HTML代码本质是字符串)转化为浏览器认识的节点,生成DOM树,也就是DOM Tree
解析css,生成CSSOM(CSS规则树)
把DOM Tree 和CSSOM结合,生成Rendering Tree(渲染树)
-当我们修改了一些元素的颜色或者背景色,页面就会重绘(Repaint)
-当我们修改元素的尺寸,页面就会重排(Reflow也叫回流)
-当页面需要Repaing和Reflow时GUI线程执行,绘制页面
-回流(Reflow)比重绘(Repaint)的成本要高,我们要尽量避免Reflow和Repaint
-GUI渲染线程与JS引擎线程是互斥的
当JS引擎执行时GUI线程会被挂起(相当于被冻结了)
GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行
JS引擎线程
-JS引擎线程就是JS内核,负责处理Javascript脚本程序(例如V8引擎)
-JS引擎线程负责解析Javascript脚本,运行代码
-JS引擎一直等待着任务队列中任务的到来,然后加以处理
浏览器同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的
一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
-GUI渲染线程与JS引擎线程是互斥的,js引擎线程会阻塞GUI渲染线程
就是我们常遇到的JS执行时间过长,造成页面的渲染不连贯,导致页面渲染加载阻塞(就是加载慢)
例如浏览器渲染的时候遇到
浏览器渲染流程
(1)解析 HTML 文件生成DOM 树
(2)解析 CSS 生成CSSOM规则树
(3)结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree),这一过程称为 Attachment
(3)遍历渲染树开始布局,计算每个节点的位置大小信息;
(4)将渲染树每个节点绘制到屏幕;
(5)浏览器主进程将默认的图层和复合图层交给 GPU 进程,GPU 进程再将各个图层合成(composite),最后显示出页面
什么是渲染层合并 (Composite) ?
渲染层合并,对于页面中 DOM 元素的绘制(Paint)是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将绘制的位图发送给 GPU 绘制到屏幕上,将所有层按照合理的顺序合并成一个图层,然后在屏幕上呈现。
浏览器渲染优化方法…
(1)针对JS:JavaScript既会阻塞HTML的解析,也会阻塞CSS的解析。因此我们可以对JavaScript的加载方式进行改变,来进行优化
尽量将JavaScript文件放在body的最后;
body中间尽量不要写<script>
标签;
< script>
标签的引入资源方式有三种:尽量使用异步加载,不会阻塞DOM的解析:
- script 立即停止页面渲染去加载资源文件,当资源加载完毕后立即执行js代码,js代码执行完毕后继续渲染页面;
- async
<script async src="script.js">
是在下载完成之后,立即异步加载,加载好后立即执行,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行,多个带async属性的标签,不能保证加载的顺序; - defer 是在下载完成之后,立即异步加载。加载好后,如果 DOM 树还没构建好,则先等 DOM 树解析好再执行;如果DOM树已经准备好,则立即执行。多个带defer属性的标签,按照顺序执行
(2)针对CSS:
使用CSS有三种方式:使用link、@import、内联样式,其中link和@import都是导入外部样式, 它们之间的区别:
link:浏览器会派发一个新等线程(HTTP线程)去加载资源文件,与此同时GUI渲染线程会继续向下渲染代码;
@import:GUI渲染线程会暂时停止渲染,去服务器加载资源文件,资源文件没有返回之前不会继续渲染(阻碍浏览器渲染);
内联样式:GUI直接渲染
因此:
在开发过程中,导入外部样式使用link,而不用@import。
如果css少,尽可能采用内嵌样式,直接写在style标签中
(3)针对DOM 、CSSOM树:可以通过以下几种方式来减少渲染的时间:
HTML文件的代码层级尽量不要太深
使用语义化的标签,来避免不标准语义化的特殊处理
(4)减少回流与重绘:
操作DOM时,尽量在低层级的DOM节点进行操作ÿ