Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器工作原理:从输入URL到页面加载完成 #55

Open
amandakelake opened this issue Sep 13, 2018 · 2 comments
Open

浏览器工作原理:从输入URL到页面加载完成 #55

amandakelake opened this issue Sep 13, 2018 · 2 comments
Labels
Web 网络、性能、优化类

Comments

@amandakelake
Copy link
Owner

amandakelake commented Sep 13, 2018

有一道经典的题目叫做从输入URL到页面加载完成的过程中发生了什么
除去一些硬件、后端,我顺着整个学习流程,查了一些资料,参考了许多前辈们的博客(再次谢过开源分享的前辈们),在前端方向总结出来的一些知识点,几乎囊括了整个前端体系,可以看到JS在整个流程里面也只是一个很小一块知识点而已(当然,一切的基础围绕JS展开)
c7fa8db7-8c9d-40c1-9636-cfca6dee370b

如果再加上性能(可以从本文延伸出来)、框架原理、工程化、安全、移动端的一些东西,几乎就是目前一个大前端的知识体系了,也是比较庞大了,不再是以前大家眼中简简单单HTML+CSS+JS走天下的时代了,过去了……路漫漫其修远兮,吾将上下而求索!

前面先捋一捋一些比较核心的基础概念,后面再细细展开,如果觉得后面逻辑有点乱了,可以回头再看看这个图,沿着脉络去看会事半功倍

一、进程和线程

  • 进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
  • 线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

查看电脑中的进程,mac可以打开活动监视器
a396974e-cfe4-467c-ac63-104ecfe3bc94

单线程与多线程,都是指在一个进程内的单和多

浏览器是多进程的
理论上:在浏览器中打开一个网页相当于新起了一个独立的浏览器进程(进程内有自己的多线程)

打开chrome的任务管理器,可以发现,有些tab的进程会被合并,这应该是浏览器的优化机制
33b6d36c-28a2-4ea7-89d8-63c17f6959fd

浏览器的进程

浏览器的主要进程有如下几个
866a7e55-2cec-4a51-b763-7043c9112499

  • Browser进程:浏览器的主进程(负责协调、主控),只有一个
负责浏览器界面显示,与用户交互。如前进,后退等
负责各个页面的管理,创建和销毁其他进程
将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
网络资源的管理,下载等
  • 第三方插件进程
每种类型的插件对应一个进程,仅当使用该插件时才创建看上面的图片中的“扩展程序”就是了
  • GPU进程:最多一个,用于3D绘制等
  • 浏览器渲染进程(浏览器内核),这是我们重点关注的进程
Renderer进程,内部是多线程的
页面渲染,脚本执行,事件处理等

浏览器多进程的优势

  • 单个tab奔溃不会影响整个浏览器
  • 避免第三方插件影响浏览器
  • 多进程充分利用多核优势

当然,这样内存也会增加,空间换时间吧

二、Browser进程与浏览器内核通信

先看个简单的宏观模型

  • Browser进程收到用户请求
  • 网络请求获取页面内容(资源下载会阻塞)
  • 渲染进程(Render进程)解析
  • 渲染线程(看清楚,是线程,不是进程)渲染网页(需要Browser进程分配资源和GPU进程的帮助)

3d8a3213-8e01-4655-838e-1a61d6336e09

网上盗图一张
7307a22d-870c-4461-9906-14bfb12f771d

三、浏览器渲染(render)进程(浏览器内核)

重点关注渲染进程,以下动作都是这个进程执行的

  • 页面的渲染
  • JS的执行
  • 事件的循环

浏览器的渲染进程是多线程的,它包含了如下线程(得区分清楚进程和线程的概念)
69a510eb-a8b5-4b1d-9e4f-49c1aa522fc7

1、GUI渲染线程

负责渲染浏览器界面,解析HTML、CSS
当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行
GUI渲染线程与JS引擎线程是互斥的,因为JS可以操作DOM元素, 从而影响到GUI的渲染结果,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行

2、JS引擎线程

JS内核(例如V8引擎),负责处理Javascript脚本程序
JS引擎一直等待着任务队列中任务的到来,然后加以处理
GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行时间过长,页面渲染就不连贯,造成页面渲染加载阻塞

3、事件触发线程

由于JS引擎这个单线程的家伙自己都忙不过来,所以需要浏览器另开一个线程协助它
待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)

4、 定时触发器线程

setInterval与setTimeout所在线程
JS引擎阻塞状态下计时不准确,所以由浏览器另开线程单独计时
计时完毕后,添加到事件队列中,等待JS引擎空闲后执行
W3C规定,setTimeout中低于4ms的时间间隔算为4ms

5、异步HTTP请求线程

如果请求有回调事件,异步线程就产生状态变更事件,将这个回调再放入事件队列中,等JS引擎空闲后执行

好了,回顾一下,浏览器是多进程的,JS是单线程的
10680d05-8f93-45d1-ac5b-ecd290d60324

四、关于浏览器渲染进程的一些概念

1、GUI渲染线程与JS线程互斥

JS可以操作DOM,如果GUI和JS线程可以用时运行,那么最后的DOM是不可预测的
所以当JS引擎执行时GUI线程会被挂起, GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行

2、WebWorker 改变了JS单线程的本质吗

Web Worker 允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM 。
所以,这个新标准并没有改变 JavaScript 单线程的本质

WebWorker SharedWorker区别

Web Workers除了WebWorker,还有SharedWorker、Service Workers
具体详看MDN
Web Workers API - Web API 接口 | MDN

大概提一下,WebWorker只是属于该render进程下的一个线程,SharedWorker由独立的进程管理,多个render进程可以共享

3、JS阻塞页面

由于JS线程和GUI线程互斥 ,所以一旦某段JS代码执行时间过长,页面渲染就会渲染不连贯,出现“加载阻塞”页面渲染的现象

从性能方面考虑,以下几个地方需要优化的

  • JS加载逻辑放到页面底部,减少JS加载对GUI渲染工作的影响
  • 避免重排/回流/Reflow(影响布局和大小的CSS样式),减少重绘/Repaint(颜色改变)
  • 避免DOM嵌套层级过深
  • 使用 requestAnimationFrame 来实现动画视觉变化,setTimeoutsetInterval 的回调在帧的某个时间点运行,如果刚好在末尾,可能导致丢帧,引发卡顿

4、CSS加载会否阻塞页面?

  • CSS是由单独的网络请求线程异步下载的
  • CSS下载不会阻塞DOM树解析(DOMContentLoaded),但会阻塞render树渲染(loaded)

因为CSS有可能会影响DOM节点,所以如果不阻塞render树渲染,有可能会造成回流(重绘倒是小事),造成不必要的性能开销

5、普通图层和复合图层

普通文档流都在一个复合图层内,绝对布局absolute/fixed也不例外,依然在这个普通图层中

可以通过硬件加速的方式来声明新的复合图层,新的复合图层不会影响默认图层内的回流重绘

* translate3d、translateZ
* opacity属性/过渡动画(动画执行过程中才会生成复合图层,其他状态依然在默认图层中)
* will-chang属性

GPU会单独分配资源,单独绘制各个复合图层,互不影响

absolute和硬件加速的区别

absolute脱离了普通文档流,但没有脱离默认复合图层
absolute中的信息变化不会影响render树,但依然会影响最终的默认复合图层的绘制,会引起重绘,所以也会消耗资源(对本页面的渲染消耗)

而硬件加速,则只会影响新的复合图层,改动后可以避免整个页面重绘
但也不能无节制的使用复合图层,否则也会引起资源消耗过度(对GPU的资源消耗)

五、从输入url到呈现页面(前端角度)

简单过一下整体流程,每一块都值得细细展开去了解更多
后面重点聊聊浏览器渲染流程

整个过程

  • DNS解析
  • TCP连接+HTTP请求
  • 浏览器解析渲染页面
  • 连接结束

1、DNS解析

首先在本地域名服务器中查询IP地址,如果没有,按照如下顺序
根域名服务器. -> 顶级域名服务器com -> …… -> 本地域名服务器
. -> .com -> google.com. -> www.google.com.

优化:DNS缓存
浏览器缓存 -> 系统缓存 -> 路由器缓存 -> ISP(运营商)DNS缓存 -> 根域名服务器 -> 顶级域名服务器com -> 主域名服务器的顺序

浏览器缓存可通过在浏览器输入chrome://net-internals/#dns查看
系统缓存在/etc/hosts文件中(linux系统)

2、TCP请求(三次握手)+ HTTP请求

客户端:我要请求数据,可以吗
服务器:可以
客户端:好的

客户机与服务器建立连接后就可以通信,浏览器向web服务器发送http请求

3、浏览器解析渲染页面

4fd56ac9-5d48-4d8a-8283-1ea65077eb5b

  1. 处理 HTML 标记并构建 DOM 树
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局,以计算每个节点的几何信息。
  5. 调用 GPU 绘制,合成图层,显示在屏幕上

DOMContentLoaded 事件触发代表初始的 HTML 被完全加载和解析,不需要等待 CSS,JS,图片加载。
Load 事件触发代表页面中的 DOM,CSS,JS,图片已经全部加载完毕。

4、连接结束,四次挥手

客户端:我没要数据要发送了,准备挂了
服务器:收到,但我还有一些数据没发送完,稍等一哈

服务端:好了,发送完了,可以断开连接了
客户端:OK,你断开连接吧(内心独白:我将会在2倍的最大报文段生存时间后关闭连接,如果再收到服务器的消息,那么服务器就是没听到我最后这句话,我就再发送一遍)

六、浏览器解析渲染页面

@westlu
Copy link

westlu commented Feb 19, 2020

你好,博文中的图片都看不到,请问是什么原因呢?

@amandakelake
Copy link
Owner Author

amandakelake commented Feb 21, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Web 网络、性能、优化类
Projects
None yet
Development

No branches or pull requests

2 participants