前端面试常考的有关浏览器方面的知识

浏览器渲染机制/浏览器渲染过程

1. 建立/更新DOM树和请求css/image/js: 浏览器请求HTML代码后 在生成DOM树最开始的阶段(字节 -> 字符) 并行发起css/image/js请求css

2. 建立/更新 CSSOM树: CSS文件下载 开始构建CSSOM树

3. 建立/更新 渲染树: 全部CSS文件下载完成后 CSSOM树构建结束和DOM树一块儿生成渲染树html

4. 布局: 经过渲染树 浏览器已经知道网页有哪些节点 各个节点CSS定义以及它们的从属关系 计算出每一个节点在屏幕中的位置

5. 绘画: 根据布局 按照算出来的规则 经过显卡 把内容画到屏幕上前端


以上五个步骤 前三步都有建立/更新是由于DOM/CSSOM/渲染树可能在第一次绘画后屡次更新 好比JS修改了DOM/CSS 布局和绘画也会被重复执行 除了DOM/CSSOM更新缘由外 图片下载完成后也须要调用布局和绘画来更新网页web

解析HTML文件的过程

1. 建立Document对象, 开始解析web页面。解析HTML元素和他们的文本内容后添加Element对象和Text节点到文档中。这个阶段的document.readyState = 'loading';

2. 遇到link外部的css,建立线程加载,并继续解析文档。chrome

3. 遇到script外部的js,而且没有设置async/defere,浏览器加载,并阻塞, 等待js加载完成并执行该脚本,而后继续解析文档。

4. 遇到script外部的js,而且设置async/defere,浏览器建立线程加载,并继续解析文档。对于async属性的脚本,脚本加载完成后当即执行。(异步禁止使用document.write())前端工程化

5. 遇到img等,先正常解析dom结构,而后浏览器异步加载src,并继续解析文档。

6. 当文档解析完成后,document.readyState = 'interactive' // domTree刚创建api

7. 文档解析完成后,因此设置有defere的脚本会按照顺序执行(注意与async的不一样,但一样禁止使用document.write())。

8. document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段 // 能够监听用户的输入事件/监听事件。数组

9. 当全部的async的脚本加载完成并执行后,img等加载完成后 document.readyState = 'complete',window对象触发Load事件。

10. 今后,以异步响应方式处理用户输入,网络事件等 浏览器

分三步
1.建立Document对象
2.解析文档
3.文档加载完并执行完缓存

思考解析HTML文件中引起的问题?

1. 加载JS和CSS会阻塞浏览器的渲染吗 下载JS和CSS会阻塞吗
2. js加载会阻塞dom的解析吗,js加载会阻塞dom的渲染吗 ?
3. css加载会阻塞dom的解析吗,css加载会阻塞dom的渲染吗 ?
4. 为何生成了CSSOM树这样的结构?

加载JS和CSS会阻塞浏览器的渲染吗 下载JS和CSS会阻塞吗

加载JS会阻塞浏览器渲染 加载CSS不会阻塞浏览器渲染 由于CSS加载是异步的

下载JS和CSS不会阻塞浏览器渲染 由于加载有个下载和解析的过程 而下载只是下载这个文件 不会读取里面的内容

js加载会阻塞dom的解析吗,js加载会阻塞dom的渲染吗 ?

js会阻塞dom的解析 但js不会阻塞dom的渲染 由于此时js代码已经所有执行完成了

css加载会阻塞dom的解析吗,css加载会阻塞dom的渲染吗 ?

1. 整个页面只引入一个外部css文件 css是不阻塞dom解析的 由于DOM解析和CSS解析是两个并行的过程 可是css会阻塞dom渲染的 由于渲染树是依赖于DOM树和CSSOM树 它必须等待到CSSOM树构建完成 也就是CSS资源加载完成或者CSS资源加载失败后 才能开始渲染 

2. css页面后面还有外部js文件 css是阻塞了dom的解析的 这是主要是由于css后面还有js 考虑到js可能会改变css属性 全部必须等到它前面的css执行完毕

img会阻塞dom的解析吗,img会阻塞dom的渲染吗 ?

一、没有外部css文件 img对dom的解析没有阻塞 可是会阻塞dom的渲染(而全部经过src属性导入的元素,都会致使页面渲染的堵塞。)

二、有外部css文件

为何生成了CSSOM树这样的结构?

浏览器的优化方式/性能优化?

前端优化的途径有不少,大体能够分为两类:页面级优化和代码级优化。

页面级优化有减小HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等等。

代码级优化有DOM操做优化、CSS选择符优化、图片优化以及HTML结构优化等等。

一丶页面级优化

1. 减小HTTP请求数(最重要最有效)       

 一个完整的请求都须要DNS寻址丶与服务器创建链接丶发送数据丶等待服务器响应丶接受数据这样一个漫长而复杂的过程 因为浏览器进行并发请求的请求数都是有上限的 所以请求数多了之后 浏览器须要分批进行请求 所以会增长用户的等待时间 会给用户形成网站速度慢这样的一个印象 即便可能用户能看到的第一屏的资源都已经请求完了 可是浏览器的进度条一直在加载

(1)从设计实现层面简化页面

若是你的页面和百度搜索的页面同样简单,那么也就不须要什么优化操做了。所以保持页面简洁、减小资源的使用是最直接的。

(2)合理设置HTTP缓存

缓存的力量是强大的,恰当的设置缓存能够大大减小HTTP请求

怎样才算是合理的设置?原则很简单:能缓存越多越久越好。

例如:不多变化的图片资源就能够直接经过HTTP Header中的Expires设置一个很长的过时头;变化不频繁而又可能会变的资源可使用Last-Modified来作请求验证。尽量的让资源可以在缓存中待的更久。

(3)资源合并与压缩

若是能够的话,尽量的将外部脚本、样式进行合并,尽量地合并为一个。另外,CSS、JS、Image均可以用相应的工具进行压缩,压缩后每每能节省很多空间。或者使用Webpack等前端工程化工具来进行代码的压缩和去重。

(4)使用雪碧图

雪碧图又叫作精灵图,咱们能够把网站中须要用到的一些icon,所有放到一个图片资源中,而后经过改变位置来获取须要的图片,这样合并CSS图片,就能够大幅度减小HTTP请求数了。 

(5)内联图片使用 

data: URL scheme的方式将图片嵌入到页面或 CSS中,若是不考虑资源管理上的问题的话,不失为一个好办法。若是是嵌入页面的话换来的是增大了页面的体积,并且没法利用浏览器缓存。使用在 CSS中的图片则更为理想一些。

(6) 懒加载

这条策略实际上并不必定能减小 HTTP请求数,可是却能在某些条件下或者页面刚加载时减小 HTTP请求数。对于图片而言,在页面刚加载的时候能够只加载第一屏,当用户继续日后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。

首页 曾经的作法是在加载的时候把第一屏以后的图片地址缓存在 Textarea标签中,待用户往下滚屏的时候才 “惰性” 加载。

(6)瀑布流

其实懒加载并不能减小HTTP请求数,他只是能够减小页面刚加载的时候的HTTP请求数,总数是不变的。对于图片而言,在页面刚加载的时候可能只加载第一屏的图片,随着用户的滚动才会继续加载后面的图片资源,这种瀑布流的加载方式就能够有效提升性能。

2. 将外部脚本放在底部

前文有谈到,浏览器是能够并发请求的,这一特色使得其可以更快的加载资源,然而外链脚本在加载时却会阻塞其余资源,例如在脚本加载完成以前,它后面的图片、样式以及其余脚本都处于阻塞状态,直到脚本加载完成后才会开始加载。若是将脚本放在比较靠前的位置,则会影响整个页面的加载速度从而影响用户体验。解决这一问题的方法有不少,而最简单可依赖的方法就是将脚本尽量的日后挪,减小对并发下载的影响。

3. 并发执行内联脚本

使用 script元素的defer 属性(存在兼容性问题和其余一些问题,例如不能使用document.write()、使用setTimeout ,此外,在HTML5中引入了 Web Workers的机制,偏偏能够解决此类问题。 

4. 懒加载

只须要在须要资源的时候才加载资源,不须要的时候就不加载资源。

5. 将CSS放在 HEAD中

若是将 CSS放在其余地方好比 BODY中,则浏览器有可能还未下载和解析到 CSS就已经开始渲染页面了,这就致使页面由无 CSS状态跳转到 CSS状态,用户体验比较糟糕。除此以外,有些浏览器会在 CSS下载完成后才开始渲染页面,若是 CSS放在靠下的位置则会致使浏览器将渲染时间推迟。

6. 把js放到整个页面的底部,另外一个方法是在script 标签上加一个 defer属性 保证让浏览器把脚本下载出来后,而后等到页面渲染完毕再执行。(参考权威指南 js时间线)

7. CSS文件用link标签加载 是阻塞状态的,咱们可使用loadCss小工具库来进行异步css文件加载,可是有一个问题是,所有异步加载css,页面最开始呈现出的只是单纯的html ,不是很好看 因此咱们要选定一个关键的css文件,用critical工具来自动提取压缩关键的css. (百度自行查看使用方法)

8. 减小没必要要的HTTP跳转

对于以目录形式访问的HTTP连接,不少人都会忽略连接最后是否带’/’,假如你的服务器对此区别对待的话,那么你也须要注意了,这其中极可能隐藏了301跳转,增长了多余请求。

 9. 避免重复的资源请求

这种状况主要是因为在模块化开发时,咱们的不一样模块之间可能有相同的部分,致使资源的重复请求

二丶 代码级优化

1. DOM 

 DOM操做应该是脚本中最耗性能的一类操做

(1)HTMLCollection(HTML收集器,返回的是一个数组的内容信息)由于是这个集合并非一个静态的集合,它表示的仅仅是一个特定的查询,每次访问该集合时都会从新执行这个 查询从而更新查询结果。所谓的“访问集合”包括读取集合的length属性、访问集合中的元素

(2)Reflow&Repaint 

 减小页面的重绘和重排。

2. 慎用with

with会改变做用域链,有可能致使咱们的做用域链变长,致使查询性能降低。

3. 避免使用eval和Function

每次 eval 或 Function 构造函数做用于字符串表示的源代码时,脚本引擎都须要将源代码转换成可执行代码。这是很消耗资源的操做—— 一般比简单的函数调用慢 100倍以上。

4. 减小做用域链查找

若是在循环中须要访问非本做用域下的变量的时候,请遍历以前用局部变量缓存的变量,并在遍历结束以后重写这个缓存变量

5. 数据访问

js中对直接量和局部变量的访问时最快的,对对象属性以及数组的访问须要更大的开销,当出现下面的状况的时候,建议将数据放入局部变量:

(1)对任何对象属性的访问超过1次

(2)对任何数组成员的访问次数超过1次

另外,要尽量的减小对对象以及数组的深度查找。

6. 字符串拼接

字符串的拼接尽量少的使用“+”,这种方式的效率是十分低下的,由于每次运行都会开辟新的内存并生成新的字符串变量,而后将拼接的结果赋值给新变量。

建议使用的是先转化为数组,而后经过数组的join方法来链接成字符串。不过因为数组也有必定的开销,所以就须要权衡一下,当拼接的字符串比较少的时候,能够考虑用“+”的方式,比较多的时候就须要考虑用数组的join方法了。


重绘和重排:页面有三个树:DOMTree、CSSTree、renderTree。(实际上多于三个),renderTree上有两个规则:repaint和reflow,重绘和重排。

重绘(repaint)是元素自身的位置和宽高不变,只改变颜色的之类的属性而不会致使后面的元素位置的变化的时候,renderTree发生的动做。

重排(reflow)是元素自身的位置或者宽高改变了从而致使的整个页面的大范围移动的时候,renderTree发生的动做。因此咱们在DOM操做的时候,要尽可能避免重排。

浏览器缓存

1. cookie

什么是cookie?

cookie是由服务端生成的 发送给User-Agent(通常是浏览器) (服务器告诉浏览器设置一下cookie) 浏览器会将cookie以key/value形式保存到某个目录下的文本文件内 下次请求同一网站时就发送该cookie给服务器(前提是浏览器设置为启动cookie)

cookie就是一个小型文件(浏览器对cookie的内存大小是有限制的 --- 用来设置一些信息)

为何会有cookie?

Web应用程序是使用HTTP协议传输数据的 HTTP协议是无状态的协议 一旦数据交换完毕 客户端和服务端的链接就会关闭 再次交换数据须要创建新的链接 这就意味着服务器没法从链接上跟踪会话

cookie的特色?

cookie有保质期

知足同源策略 (不一样域的话能够在服务端设置document.domain或path来实现共享)

cookie内存大小受限制(cookie有个数和大小的限制 大小通常是4K)

注意?

cookie在本地 能够被更改的文件 敏感数据不要放在cookiel里

// 本身封装设置cookie的代码
var manageCookie = {    setCookie: function(name, value, time) {        document.cookie = name + '=' + value + ';max-age' + time;        return this;    },    removeCookie: function(name) {        return this.setCookie(name, '', -1);    },    getCookie: function(name, callback) {        var allCookieArr = document.cookie.split('; ');        for(var i = 0; i < allCookieArr.length; i++) {            var itemCookieArr = allCookieArr[i].split('=');            if(itemCookieArr[0] === name) {                callback(itemCookieArr[1]);                return this;            }        }        callback(undefined);        return this;    }}复制代码

2. http缓存

http缓存是基于HTTP协议的浏览器文件级缓存机制

即针对文件的重复请求状况下 浏览器能够根据协议头判断从服务器端请求文件仍是从本地读取文件 chrome控制台下的Frames即展现的是浏览器的http文件级缓存 

如下是浏览器缓存的这个机制流程 主要针对重复的http请求 在有缓存的状况下判断过程主要分为3步

判断expires 若是未过时 直接读取http缓存文件 不发http请求 不然进入下一步

判断是否含有etag 有则带上if-none-match发送请求 未修改返回304 修改返回200 不然进入下一步 

判断是否含有last-modified 有则带上if-modifined-since发送请求 无效返回200 有效返回304 不然直接向服务器请求

若是经过etag和last-modifined判断 即便返回304有至少有一次http请求 只不过返回的是304的返回内容 而不是文件内容 因此合理设置实现expires参数能够减小较多的浏览器请求

3. localstorage

localStorage是HTML5的一种新的本地缓存方案 目前用的比较多 通常用来存储Ajax返回的数据 加快下次页面打开时的渲染速度

经常使用API

localStorage.setItem(key, value); // 设置记录

localStorage.getItem(key); // 得到记录

localStorage.removeItem(key); // 删除该域名下单条记录

localStorage.clear(); // 删除该域名下全部记录

注意: localStorage大小有限制 不适合存放过多的数据 若是数据存放超过最大限制会报错 并移除最早保存的数据

4. sesstionStorage

sesssionStorage和localStorage相似 可是浏览器关闭则会所有关闭 api和localStorage相同


.......未完待续

你的点赞是我持续输出的动力 但愿能帮助到你们 互相学习 有任何问题下面留言 必定回复

相关文章
相关标签/搜索