在我刚开始学习Web开发的时候,一直有个疑问——我写出的代码究竟是在什么时候发生作用的呢?是不是每次我修改代码网页都随之变化了?当然,现在来看这肯定是一个错误的想法,经过一段时间的工作和学习后,代码到页面转换的路径在我的脑海里愈发清晰,虽然“输入URL到网页显示之间发生了什么?”是个老生常谈的问题,但我还是想按自己的理解来说明一遍。
浏览器架构
首先从我们最熟悉的朋友开始说起,Web开发离不开浏览器,我在查资料的时候有开很多选项卡的习惯,每次打开任务管理器都能看到Chrome浏览器在内存占用方面一枝独秀,另外还能看到应用名称后面的括号里有个数字,如下图所示,但我打开的标签页是不到23的,那么剩下的进程是什么呢?
我们来看一张经典的图,它描绘了Chrome浏览器中四种进程的位置和作用:
- 浏览器进程 (Browser Process):负责浏览器的TAB的前进、后退、地址栏、书签栏的工作和处理浏览器的一些不可见的底层操作,比如网络请求和文件访问。
- 渲染进程 (Renderer Process):负责一个Tab内的显示相关的工作,也称渲染引擎。
- 插件进程 (Plugin Process):负责控制网页使用到的插件
- GPU进程 (GPU Process):负责处理整个应用程序的GPU任务
渲染进程较为特殊,每个选项卡里都需要一个渲染进程,它也是网页渲染的核心,我们在下一节详细说明,关于这些进程,可以在浏览器自带的进程管理器中详细查看:
由于经常要做多浏览器兼容,经常同时打开几个浏览器,即使没有仔细对比还是可以发现Chrome浏览器在内存占用方面算是相对比较高的,而Firefox则相对要低很多,这是因为Firefox的Tab进程和IE的Tab进程都采用了类似的策略:有多个Tab进程,但都不一定是一个页面一个Tab进程,一个Tab进程可能会负责多个页面的渲染。而作为对比,Chrome是以一个页面一个渲染进程,加上站点隔离的策略来进行的。虽然内存占用确实比较高,但是这种多进程架构也有独特的优势:
- 更高的容错性。当今WEB应用中,HTML,JavaScript和CSS日益复杂,这些跑在渲染引擎的代码,频繁的出现BUG,而有些BUG会直接导致渲染引擎崩溃,多进程架构使得每一个渲染引擎运行在各自的进程中,相互之间不受影响,也就是说,当其中一个页面崩溃挂掉之后,其他页面还可以正常的运行不收影响。
- 更高的安全性和沙盒性(sanboxing)。渲染引擎会经常性的在网络上遇到不可信、甚至是恶意的代码,它们会利用这些漏洞在你的电脑上安装恶意的软件,针对这一问题,浏览器对不同进程限制了不同的权限,并为其提供沙盒运行环境,使其更安全更可靠
- 更高的响应速度。在单进程的架构中,各个任务相互竞争抢夺CPU资源,使得浏览器响应速度变慢,而多进程架构正好规避了这一缺点。
网页渲染
大致来说,输入URL后要经过五个步骤网页才会渲染完成:
- DNS 查询
- TCP 连接
- HTTP 请求即响应
- 服务器响应
- 客户端渲染
首先,如果输入的是域名,浏览器会先从hosts文件中查找有没有对应的设置,如果没有则访问附近的DNS服务器进行DNS查询获取正确的IP地址,之后进行TCP连接,通过三次握手建立连接后开始处理HTTP请求,服务器端收到请求返回响应文档,拿到响应文档的浏览器开始使