从浏览器渲染到性能优化

885 阅读22分钟

image.png

一、认识浏览器

浏览器 目前算是大部分人身边必不可少的存在了,大到使用电脑、小到使用手机时,我们搜索信息、查看某个网站等,可能都在使用浏览器进行搜索。当然它也成为了我们绝大部分业务的展现形式,比如我们给客户开发的系统,用户会在电脑/手机上打开浏览器输入网址进行相关的业务操作... ...是不是感觉浏览器跟我们还挺熟的,但是你了解它么???

那么,接下来由我带领大家重新认识下我们熟悉而又陌生的 浏览器

1.1、发展历程

  • 起源

”1994年,网景通信公司推出了代号为 “网景导航者” 的网景浏览器 1.0,随后迭代版本迅速占领浏览器大部分份额。

公司一看浏览器业务这么好,那干脆试着做一个操作系统得了,微软意识到网景通讯公司对其操作系统和应用市场的威胁,立马收购另外一家浏览器公司,在其基础上开发了 Internet Explorer,微软的操作系统和 IE 浏览器捆绑销售,想想当时的场景,安装一个微软的操作系统没有浏览器,还需要再花钱买一张网景浏览器软件安装在电脑上才能上网,尽管网景浏览器很好用,但这样也很麻烦。微软操作系统中直接带有浏览器,试问还有谁愿意去在花钱买个浏览器软件?所以 IE 立马占领了浏览器市场。1998年1月,网景与微软IE浏览器竞争失利以后,为了挽回市场,网景通信公司公布旗下所有软件以后的版本皆为免费,并开放网景浏览器的源代码,成立了非正式组织 Mozilla,自此 Mozilla 浏览器开始登上舞台。可惜的是尽管 Mozilla、opera 浏览器很好用,可微软操作系统的市场占有率很大,造成其他浏览器的市场份额一直不变。IE坐在份额第一的头把交椅后,却一直不思进取,自己制作一套web标准,也不怎么支持html,javascript,css这些web技术的新版本特性,微软从ie6开始到ie8七八年间几乎没对浏览器做什么革新,大家都适应了IE,什么补丁、不安全、崩溃也不在意,也觉得浏览器就该如此。可现实就是这么捉摸不定,变幻莫测,2008 年 chrome横空出世。界面简洁、加载快速、数据安全等这些特点让 chrome 的市场份额逐步攀升。当微软意识到chrome开始逐步侵蚀自己的市场时,开始频繁更新IE,2011年IE9发布,2012年IE10发布,2013年IE11发布,最后IE的代码实在适应不了新的要求的web技术,就重新开发了一个名为”edge"的浏览器用来取代IE,但还是挡不住chrome成为市场份额第一的命运。在IE横行的那一段时间为了适应IE中国的大多数常用网站也不大符合互联网标准,也就是说如果用符合互联网标准的浏览器去解析这些网站,反而会不正常显示,可见IE坐头把交椅的这几年,却一直在误导和阻挠互联网的发展,悲哉啊。在此要向那些不断创新、不断完善、不断接纳新web技术的浏览器公司,面对IE他们的市场份额不高,却仍然坚持着不断前进。”

”自从chrome浏览器出现后,就出现了很多国产浏览器,这是后话,其实国产浏览器的起源于IE,一位网名为changyou(畅游)的程序员于1999年在论坛上发布一款叫”MyIE"的浏览器,基于IE,但采用多窗口浏览,占用系统资源比IE6少很多,且有鼠标手势、视觉化书签等功能,后来的中国浏览器MyIE2(后改名Maxthon)、网际畅游(后改名GreenBrowser)与TheWorld(世界之窗)等都是用MyIE的源代码改写完成。这几款浏览器都不是开发MyIE那位维护的,MyIE版本到3.2版本后就再也没有更新过,“畅游”这个人也消失不见了。后来呢遨游成立公司独自运营,TheWorld被360收购变成了360安全浏览器。”

以上内容摘自 www.jianshu.com/p/c1c2737f1…

  • 各大浏览器市场占有率

chrome 是 google 于 2008 年 9 月发布的一款浏览器,以其 “快速、简单、安全” 的特点在短短几年占领份额第一。除了 chrome,目前主流的浏览器还有 IE、Firefox、Safari、Opera,国内浏览器有遨游、世界之窗、搜狗浏览器、360安全浏览器、QQ浏览器、猎豹浏览器等。以下数据截图来源于 gs.statcounter.com/

1.2、工作原理

  • 客户端与服务端交互

三次握手建立连接、客户端发送响应头、信息等,服务器响应信息、四次挥手断开连接

  • 进程/线程

我们现在熟知的 windows MacOS Linux 等,都属于 '多任务' 操作系统。 什么是多任务呢?简单的说,就是操作系统上可以同时运行多个任务/程序。比如:同时打开代码编辑器、浏览器,我们可以边写代码,边在浏览器中看到效果。或者有的人喜欢边听音乐、边写代码(有情调、有氛围)。

这里提到的多个任务跟程序就是进程。理论上来说一个应用程序就是一个进程,比如打开一个浏览器就启动了一个浏览器主进程

进程(Process)

是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程(thread)

是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

  • Chrome 浏览器

我们常用的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。

  • 使用同一个浏览器进程

我们将 同一站点 定义为根域名(例如: xx.che300.com)加上协议(例如: https://http://),还包含了该根域名下的所有子域名和不同的端口,如下所示:

https://xx.che300.com
https://xx.che300.com/bi

它们都是属于同一站点,因为它们的协议都是 HTTPS,而且根域名也都是 xx.che300.com。Chrome 的默认策略是,每个标签对应一个渲染进程。但如果从一个页面打开了另一个新页面,而新页面和当前页面属于同一站点的话,那么新页面会复用父页面的渲染进程。官方把这个默认策略叫 process-per-site-instance。如果使用右键 在新标签页中打开链接,即使是同一站点也不会使用同一个进程。

1.3、渲染过程

常见问题:在浏览器地址栏中输入地址到渲染出整个页面,中间经历了什么?

你需要了解浏览器渲染页面的前提是需要加载: HTML、CSS、JavaScript 文件

用户在浏览器地址栏中输入内容,浏览器引擎会先识别内容是否为网址,若不是则会调用浏览器的搜索引擎进行信息搜索,否则会进行以下过程:

  • DNS域名解析:当输入的网址是域名时,需要进行DNS解析成服务器的真实IP

查看本地 hosts 文件 -> 避免 DNS 查找(用户一般不会去修改 hosts 文件) 查看本地缓存 -> 若缓存中没有则会进行迭代查找 DNS 根服务器 负责 .com 域服务器 负责 .che300.com 域务器 获取到IP地址的同时写入本地缓存

  • 建立 TCP 连接:三次握手建立 TCP 连接,返回带有 ACK 的数据包,表示连接成功

第一次握手:客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手

  • 发送 HTTP 请求:完成 TCP 连接后,向服务器发起请求

  • 服务器处理请求:接收到请求后,服务器端进行处理

  • 返回响应结果: 向客户端返回响应信息

  • 关闭 TCP 连接:四次挥手关闭 TCP 连接,避免服务器与客户端的资源浪费

第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当 然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但此时主动关闭方还可以接受数据。 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

  • 解析 HTML 生成 DOM

  • 解析 CSS 生成 CSSOM

  • 将 DOM 与 CSSOM 合成 渲染树

  • 布局(Layout):根据渲染树,计算他们在设备视口内的确切位置和大小(回流 Reflow)

  • 绘制(Painting):根据渲染树以及布局得到的几何信息,得到节点的像素(重绘 Repaint)

  • 合成后的信息展示在界面上

1.4、渲染机制

  • TCP 连接、数据传输再到关闭的一个完整过程:

  • GUI 渲染进程

GUI(Graphical User Interface) 图形用户界面,也就是展示到浏览器提供给用户看到的页面。

在生成页面的过程中,至少会渲染一次,而在用户访问的过程中,也会不断的触发回流(重排)和重绘。无论是触发哪种,都会影响浏览器的性能。但一般来说,回流(重排)的影响会比重绘要大。

回流(重排):元素的大小、位置等发生变化时,需要重新计算几何信息,页面会重新布局、元素重新按照几何信息进行排序

重绘:修改元素的外观样式时,比如字体颜色、背景色等不需要重新计算几何信息的样式,元素进行重绘

注意:重绘不一定导致回流(重排),但回流(重排)一定会导致重绘。

二、浏览器安全

2.1、同源策略:为什么 XMLHttpRequest 不能跨域请求资源?

如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源。

通过在一个页面中运行脚本来修改另一个页面的 DOM(第二个页面必须是从第一个页面中打开)

let pdom = opener.document;
pdom.body.style.display = 'none';

注意:opener 就是指向第一个页面的 window 对象,我们可以通过操作 opener 来控制第一个页面中的 DOM。

Web 世界是开放的,可以接入任何资源,而同源策略要让一个页面的所有资源都来自于同一个源,也就是要将该页面的所有 HTML 文件、JavaScript 文件、CSS 文件、图片等资源都部署在同一台服务器上,这无疑违背了 Web 的初衷,也带来了诸多限制。

开发人员在正常请求接口时发现控制台提醒我们 http://127.0.0.1:7071/api/admin/userLogin 接口被 CORS 策略阻止:

因为访问同源的资源是被浏览器允许的,但访问不同源的资源时,浏览器默认是不允许的,即跨域。

假如将不同的资源部署到服务器上,访问的域名不同,那么就需要打破浏览器设定的这种安全策略,需要同源策略对页面的引用资源开一个“口子”,让其任意引用外部文件。为了解决类似的问题,引入了 跨域资源共享跨文档消息机制

2.2、XSS:为什么Cookie中有HttpOnly属性?

XSS(Cross Site Scripting) 攻击,又称跨站脚本攻击,是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。

针对这些 XSS 攻击,主要有三种防范策略:

  • 通过服务器对输入的内容进行过滤或者转码 服务器端将一些关键的字符进行转码,经过转码的 script 脚本将无法再执行。

  • 实施严格的 CSP 可以有效地防范 XSS 攻击

    限制加载其他域下的资源文件,这样即使黑客插入了一个 JavaScript 文件,这个 JavaScript 文件也是无法被加载的 禁止向第三方域提交数据,这样用户数据也不会外泄 禁止执行内联脚本和未授权的脚本 提供上报机制,这样可以帮助我们尽快发现有哪些 XSS 攻击,以便尽快修复问题

  • HttpOnly 保护重要的 Cookies 信息

XSS 一般是用来攻击 Cookie 中的数据,因此可以通过使用 HttpOnly 属性来保护我们 Cookie 的安全,使用 HttpOnly 是标记了 Cookie 只能使用在 HTTP 请求过程中,所以无法通过 JavaScript 来读取这段 Cookie。

2.3、CSRF:陌生链接不要随便点

CSRF(Cross-site request forgery) 攻击,又称跨站请求伪造,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。

经常会被做网络安全的同学提醒:不要点击陌生的网站链接,小心有病毒。但是为什么点了链接之后就可能中病毒呢

2.4、安全沙箱:页面和系统之间的隔离墙

由于渲染进程需要执行 DOM 解析、CSS 解析、网络图片解码等操作,如果渲染进程中存在系统级别的漏洞,用户的操作就有可能让恶意的站点获取到渲染进程的控制权限,进而又获取操作系统的控制权限,黑客会利用这些操作对含有漏洞的浏览器发起攻击。于是渲染进程和操作系统之间建立了一道墙,即便渲染进程由于存在漏洞被黑客攻击,但由于这道墙,黑客就获取不到渲染进程之外的任何操作权限。将渲染进程和操作系统隔离的这道墙就是所谓的安全沙箱。

  • 您的连接不是私密连接

2.5、HTTPS:让数据传输更安全

浏览器安全主要划分为三大块内容:页面安全、系统安全和网络安全。

起初设计 HTTP 协议的目的很单纯,就是为了传输超文本文件,那时候也没有太强的加密传输的数据需求,所以 HTTP 一直保持着明文传输数据的特征。但这样的话,在传输过程中的每一个环节,数据都有可能被窃取或者篡改,这也意味着你和服务器之间还可能有个中间人,你们在通信过程中的一切内容都在中间人的掌握中。

HTTPS 并非一个新的协议,而是在 HTTP 协议栈中引入安全层(SSL/TLS),所有的数据都会经过加密与解密。通常 HTTP 直接和 TCP 通信,HTTPS 则先和安全层通信,然后安全层再和 TCP 层通信。也就是说 HTTPS 所有的安全核心都在安全层,它不会影响到上面的 HTTP 协议,也不会影响到下面的 TCP/IP,因此要搞清楚 HTTPS 是如何工作的,就要弄清楚安全层是怎么工作的。

总的来说,安全层有两个主要的职责:对发起 HTTP 请求的数据进行加密操作和对接收到 HTTP 的内容进行解密操作。

对应的加密方案有以下几种:

对称加密 非对称加密 对称加密与非对称加密搭配使用 添加数字证书 ... ...

HTTPS 的安全性还有很多知识需要我们去探索,在这里我就不班门弄斧了,毕竟我了解的也比较浅层。

三、认识性能优化

3.1、什么是前端性能优化

从用户开始访问网站到整个页面完整地展现出来的过程中,通过各种优化策略和优化方法,让页面加载得更快,让用户的操作相应更及时,给用户更好的使用体验。

3.2、意义(用户角度)

  • 要想成为一名合格的开发者,需要具备一项重要的技能 要能站在用户体验角度来考虑页面性能

这里的页面加载时长、用户交互反馈时长、Web 动画中的帧数都决定了用户体验的流畅度,并最终决定了用户体验的效果。

当用户请求一个网站时,如果在 1 秒内看不到关键内容,用户会产生任务被中断的感觉。

当用户点击某些按钮时,如果 100ms 内无法响应,用户会感受到延迟。

如果 Web 中的动画没有达到 60fps,用户会感受到动画的卡顿。

3.3、重要性(开发角度)

  • 为什么访问这个网页这么慢

  • 提升用户体验

前端工程化包括编译、打包、发布流程、组件化等都侧重于 提效,而性能优化则侧重于 用户体验

前端框架:插件化(jQuery) -> 模块化(RequireJS) -> 组件化(React)

构建工具:任务化(grunt/gulp) -> 系统化(webpack)

CI/CD:工具化(Jenkins) -> 自动化(Web Hook)

性能优化:作为前端开发,可能需要站在用户的角度,开发功能实现交互,优化页面渲染

线上监控:捕捉用户访问过程中出现的异常情况,做相应的修复和优化

  • 自身发展 -> 你的核心竞争力在哪?

职级晋升时,被问到你的核心竞争力在哪时,答案除了 技术深度、前端工程化、综合素质等之外还能增加一个 性能优化,毕竟它可能会贯穿于开发和维护的全过程。

四、性能优化的过程

4.1、分析工具

4.1.1、Chrome DevTools

通过浏览器自带工具或者接入性能监控的SDK (即配置 Performance)可以分析出页面的性能指标,提炼出我们需要的指标值,生成页面报告,分析报告页并找出页面的性能瓶颈。

前端组自研了前端监控相关的SDK及系统管理 监控平台

4.1.2、LightHouse

需要安装 Lighthouse 扩展程序,在浏览器的开发者工具中可以看到,分析页面并生成报告,各项指标分值,还会提供一些优化建议

4.1.3、PageSpeed

需要安装 PageSpeed Insights 扩展程序,分析页面并生成报告,提供单个指标的耗时、建议以及相关分类。

4.1.4、webpack-bundle-analyzer

分析前端项目打包后的资源大小及内部模块、插件等。

4.1.5、WebPageTest ...

还有更多工具,比如 WebPageTest 等。

4.2、性能指标

  • 白屏

    是指从用户输入网址,到浏览器开始显示内容的时间

  • 首屏

    是指浏览器从响应用户输入网址,到首屏内容渲染完成的时间

  • 完全加载

    也称为页面加载,指页面加载完成的时间

  • 可交互

    是指从浏览器开始请求的时间点到用户可以正常进行事件输入等操作的时间点

  • 资源加载

    页面中资源加载完成的时间

4.3、优化方案

前面提到的分析工具及指标,可以得到一些优化点击建议,你以为性能优化就这么?在实际的项目中可优化点远远不止于此,那么所谓的性能优化到底可以错哪些。

4.3.1、文件压缩

  • 代码压缩

正式上线的代码,无特殊情况需要经过压缩,保证适当的文件大小。

  • Tree-shaking

为了提高效率前端实施了工程化打包部署等,那么假如项目中存在一些未使用到的代码或者模块是否可以直接移除呢? 答案是肯定的:

低版本的打包配置可以借助 Tree-shaking 插件,通常用于移除 JavaScript 上下文中的未引用代码 新版本的 webpack 扩展了检测能力,通过配置属性可以在打包时移除未使用的代码

  • Code-splitting

代码拆分(代码分割),通常情况下(单页面应用)前端打包的代码会生成一个 html、css、js 文件。加入项目中的组件、模块比较多,那么打包出来的js势必也会很大,单次加载时间越长,等待时间就越长,用户体验就越差,于是引入了 代码拆分 的概念,也就是按照模块(路由)打包成一个文件,同时出去模块中重复引入的部分,页面加载过程中实施动态引入(路由按需加载)的方案,这样初始化页面时等待的时间不至于太久。

4.3.2、图片优化

  • 小图优化、图片格式选择

采用 雪碧图(css sprite)、iconfont、dataURI、svg等

  • 压缩图片

压缩图片的大小(尽量在保证画质的前提下缩小图片大小),可以使用代码压缩、在线工具(tinypng)等。

  • 响应式图片

通过设置 img 标签的 srcset 属性,详细介绍可参考 www.ruanyifeng.com/blog/2019/0…

4.3.3、加载策略

  • 懒加载

延迟加载(懒加载) 是一种将资源标识为非阻塞(非关键)资源并仅在需要时加载它们的策略。 这是一种缩短关键渲染路径长度的方法,可以缩短页面加载时间。

  • DNS预解析、预加载、预渲染

  • 离线化(ServiceWorker、AppCache、离线包等)

  • HTTP缓存

  • 数据缓存(localStorage、sessionStorage)

  • 资源加载(顺序、位置、异步等)

  • 请求合并

  • HTTP2

  • CDN

  • 服务端渲染

4.3.4、执行渲染

  • CSS代码优化(选择器、启用GPU、避免表达式等)
  • JS代码优化及评估

4.3.5、感官体验优化

  • 骨架屏(Skeleton)

  • Loading(加载中)

前两种均是在页面未完全加载出来前,避免页面空白可使用 骨架屏/Loading 代替展示,提供视觉上的体验。

  • SPA(单页应用)

随着前端工程化的发展,很多项目采用 SPA 方式,采用代码分割的方式,根据检查捆绑包的大小,适时的进行按需加载。

  • Snapshot(快照、备份)

讲究的是兼顾数据的同时能够保证用户的体感,比如 接口缓存、HTML 缓存等

以上只是鄙人在学习工作中的一些小小认识与见解。本文也只是针对浏览器相关的知识做了一个简述,实际上还有很多需要细化的知识点等待大家去学习总结,欢迎指点,谢谢。


南京三百云信息科技有限公司(车300)成立于2014年3月27日,是一家扎根于南京的移动互联网企业,目前坐落于南京、北京。经过7年积累,累计估值次数已达52亿次,获得了国内外多家优质投资机构青睐如红杉资本、上汽产业基金等。
三百云是国内优秀的以人工智能为依托、以汽车交易定价和汽车金融风控的标准化为核心产品的独立第三方的汽车交易与金融SaaS服务提供商。

欢迎加入三百云,一起见证汽车行业蓬勃发展,期待与您携手同行!
Java开发、Java实习、PHP实习、测试、测开、产品经理、大数据、算法实习,热招中...
官网:www.sanbaiyun.com/
投递简历:hr@che300.com,请注明来自掘金😁