浏览器是如何工作的
Posted sameen1900
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浏览器是如何工作的相关的知识,希望对你有一定的参考价值。
学习浏览器工作原理的好处:不但是前端面试的常考知识点,它还会辅助你的实际工作,学习浏览器的内部工作原理和个中缘由,对于我们做性能优化、排查错误都有很大的好处。
过程:
- 浏览器首先使用 HTTP 协议或者 HTTPS 协议,向服务端请求页面;
- 把请求回来的 html 代码经过解析,构建成 DOM 树;
- 计算 DOM 树上的 CSS 属性;
- 最后根据 CSS 属性对元素逐个进行渲染,得到内存中的位图;一个可选的步骤是对位图进行合成,这会极大地增加后续绘制的速度;
- 合成之后,再绘制到界面上。
从 HTTP 请求回来,就产生了流式的数据,后续的 DOM 树构建、CSS 计算、渲染、合成、绘制,都是尽可能地流式处理前一步的产出:即不需要等到上一步骤完全结束,就开始处理上一步的输出,这样我们在浏览网页时,才会看到逐步出现的页面。
HTTP 协议
HTTP 协议是基于 TCP 协议出现的,对 TCP 协议来说,TCP 协议是一条双向的通讯通道,HTTP 在 TCP 的基础上,规定了 Request-Response 的模式。这个模式决定了通讯必定是由浏览器端首先发起的。
HTTP 协议格式
HTTP Method(方法)
- GET
- POST
- HEAD
- PUT
- DELETE
- CONNECT:CONNECT 现在多用于 HTTPS 和 WebSocket
- OPTIONS
- TRACE(OPTIONS 和 TRACE 一般用于调试,多数线上服务都不支持)
HTTP Status code(状态码)和 Status text(状态文本)
1xx:临时回应,表示客户端请继续。(1xx 的状态被浏览器 HTTP 库直接处理掉了,不会让上层应用知晓。)
2xx:请求成功。
200:请求成功。
3xx: 表示请求的目标有变化,希望客户端进一步处理。
301&302:永久性与临时性跳转。
304:跟客户端缓存没有更新。
4xx:客户端请求错误。
403:无权限。
404:表示请求的页面不存在。
418:It’s a teapot. 这是一个彩蛋,来自 ietf 的一个愚人节玩笑。(超文本咖啡壶控制协议)5xx:服务端请求错误。
500:服务端错误。
503:服务端暂时性错误,可以一会再试。
ps:
3xx 系列比较复杂,301 和 302 两个状态表示当前资源已经被转移,只不过一个是永久性转移,一个是临时性转移。实际上 301 更接近于一种报错,提示客户端下次别来了。
304 又是一个每个前端必知必会的状态,产生这个状态的前提是:客户端本地已经有缓存的版本,并且在 Request 中告诉了服务端,当服务端通过时间或者 tag,发现没有更新的时候,就会返回一个不含 body 的 304 状态。
HTTP Head (HTTP 头)
请求头:
响应头
HTTP Request Body
body 格式
- application/json
- application/x-www-form-urlencoded
- multipart/form-data
- text/xml
HTML 的 form 标签提交产生的 HTML 请求,默认会产生 application/x-www-form-urlencoded 的数据格式,当有文件上传时,则会使用 multipart/form-data。
HTTPS
HTTPS 有两个作用,一是确定请求的目标服务端身份,二是保证传输的数据不会被网络中间节点窃听或者篡改
HTTPS 是使用加密通道来传输 HTTP 的内容。但是 HTTPS 首先与服务端建立一条 TLS 加密通道。TLS 构建于 TCP 协议之上,它实际上是对传输的内容做一次加密,所以从传输内容上看,HTTPS 跟 HTTP 没有任何区别。
HTTP 2 是 HTTP 1.1 的升级版本
HTTP 2.0 最大的改进有两点,一是支持服务端推送,二是支持 TCP 连接复用。
此文章为4月Day6学习笔记,内容来源于极客时间《重学前端》,推荐该课程。
V8 引擎是如何工作的?
V8 引擎是如何工作的?
本文翻译自:How the V8 engine works?
? V8是谷歌德国开发中心构建的一个JavaScript引擎。它是由C++编写的开源项目,同时被客户端(谷歌浏览器)和服务器端(Node.js)应用使用。
? V8最初是为了提高web浏览器中的JavaScript运行性能设计的。为了提升性能,V8将JavaScript代码翻译为更高效的机器语言,而不是使用解释程序。它通过实现一个JIT(Just-In-Time,即时)编译器来将JavaScript代码编译为机器语言,就像很多现代JavaScript引擎如SpiderMonkey或Rhino(Mozilla)做的那样。V8和它们主要的区别是它不会生成字节码或其他中间代码。
? 本篇文章主要目的是展示和理解V8是如何为了生成优化代码工作的(为了客户端或服务器端应用)。如果你有过"我应该在乎JavaScript的性能么?"这样的疑惑,我会引用Daniel Clifford (V8团队的研发组长与经理)的这句话来回答你:
它不仅仅是为了让你现在的应用运行得更快,它是为了将不可能变为可能。
Hidden class
? JavaScript是一个基于原型的语言:在使用克隆进程的时候,并不会产生类和对象。JavaScript还是动态类型的:类型和类型信息并不明确,对象的属性也可以动态的添加或删除。如何高效地访问类型和属性是V8的第一个大的挑战。并不像大多数JavaScript引擎做的那样使用类字典数据结构存储对象属性并动态查找属性位置,V8在运行时创建hidden classes(隐藏类)来生成一个内部的类型系统表示和提高属性访问速度。
举个例子,我们创建一个Point
构造函数和两个Point
对象:
如果布局相同,以这个例子为例,p
和 q
属于相同的V8创建的hidden class。这还显示出了使用hidden classes的另一个优点:它让V8可以将属性相同的对象划为一组。在这里 p
和 q
使用相同的优化代码。
现在假设我们想要在声明之后再给 q
对象添加一个 z
属性(这对动态类型语言来说很正常)。
V8会如何处理这种情况?实际上,V8在每一次构建函数声明新的属性是都会创建一个新的hidden class,并持续跟踪hidden class 的变化。为什么?因为如果创建了两个对象(p
和 q
),在创建后第二个对象q
又被添加了一个属性,V8需要在保持上一个创建的hidden class(为第一个对象 p
创建) 的同时,为新的动态添加的属性创建一个新的hidden class(为第二个对象 q
创建)。
每次创建一个新的hidden class时,前一个hidden class都进行一次类转换更新,指示要使用哪个hidden class而不是它。
代码优化
因为V8为每一个属性创建一个新的hidden class,hidden class的创建应该尽量少。因此,我们需要尽量避免在对象创建后添加属性,同时以相同的顺序初始化对象成员(来减少hidden classes的不同树的创建)。
单态操作(Monomorphic operations)指只在对象上的使用相同hidden class的操作。V8在我们调用函数时会新建一个hidden class。如果我们使用不同的参数类型再次调用此函数,V8需要创建另一个hidden class:因此尽量编写单态代码而不是多态代码。
V8优化JavaScript代码的更多例子
切换值
为了更高效地描述数和JavaScript对象,在V8中,两者均使用32位值表示。其中1位表示这个值是对象(flag = 1
)还是数(flag = 0
)。如果一个数比31位大,V8会把它转换为double存储在新建的一个对象中。
代码优化:如果可能的话,尽量使用31位有符号数,来减少上述的高代价的操作。
数组
V8使用两种不同的方法来操作数组:
- 快速元素(Fast elements):为无间隙的密集数组设计。它们使用线性存储缓存,使得访问非常高效。(
[1,2,4,5,8]
) - 字典元素(Dictionary elements):为有间隙的稀疏数组设计。使用哈希表缓存,较之快速元素访问代价更高。(
[1,2,,5,8]
)
代码优化:尽量使用 V8 会使用快速元素方法来操作的数组。即减少使用键不是递增数的数组的使用。同时,尽量避免预分配大数组。在使用中让它自己慢慢增加会更好。同时,不要删除数组中的元素:它会使得数组稀疏。
V8如何编译JavaScript代码?
V8有两个编译器:
- 一个是"完整"编译器,可以编译任何的JavaScript代码:编译结果为好的代码但不是好的JIT代码。这个编译器的目的就是快速生成代码。为了实现这个目的,它不会进行任何的类型分析,因此它对类型一无所知。相反的,它使用内联缓存(Inline Caches)策略来在程序运行中精炼类型信息。内联缓存非常高效,带来了20倍的速度提升。
- 另一个是优化编译器,可以编译大多数JavaScript代码,生成更好的代码。它出现的更晚,并对热函数进行了重编译。优化编译器从内联缓存中获取类型并决定如何对代码进行优化。然而,有些语言特性并没有被支持或可能会抛出错误。(应对方法是使用try catch)
代码优化:V8同样支持去优化:优化编译器根据从内联缓存中获取的类型信息进行优化,当此优化后有问题时会去优化。例如,如果生成的hidden class不是期望的那样,V8会抛弃优化代码,返回到完整编译器生成的代码,并从内联缓存中重新获取类型。这个过程很慢,因此应尽量在函数被优化后不去修改它。
参考资料
- Google I/O 2012 “Breaking the JavaScript Speed Limit with V8” with Daniel Clifford, tech lead and manager of the V8 team: video and slides.
- V8: an open source JavaScript engine: video of Lars Bak, V8 core engineer.
- Nikkei Electronics Asia blog post: Why Is the New Google V8 Engine So Fast?
以上是关于浏览器是如何工作的的主要内容,如果未能解决你的问题,请参考以下文章