21 | Chrome开发者工具:利用网络面板做性能分析
页面是浏览器的核心,浏览器中的所有功能都是服务于页面的,Chrome开发者工具又是调试页面的核心工具。
网络面板
- 控制器
- 开始或停止抓包
- 全局搜索
- 禁止从cache中加载资源
- 模拟网络
- 过滤器
- 抓图信息:Capture screenshots
- 详细列表:本节重点内容
- 下载信息概要
- DOMContentLoaded:页面已经构建好DOM,所需要的HTML、CSS和JS文件都已经下载完成
- Load:浏览器已经加载了所有的资源(图片、样式表等)
详细信息中的Timing
- Queued:排队—资源优先级、6个TCP链接。
- Stalled:其它一些可能导致连接过程被推迟的原因。
- Proxy Negotiation:代理协商阶段
- Initial connection/SSL:与服务器建立连接的阶段
- Request sent:网络进程准备请求数据,发送给网络,时间通常不到1ms。
- Waiting(TTFB):第一字节时间,反映服务端相应速度的重要指标。
- Connect Download:从第一字节时间到接收到全部响应数据所用的时间。
优化Timing
1. Queuing时间太久
大概率因为每个域名同时维护6个TCP连接,基于这个原因可以使用域名分片技术,即把该站点下面的资源放在多个域名下。 另外可以将站点升级至HTTP2,因为HTTP2下面已经没有每个域名同时维护6个TCP连接的限制了(可通过curl -I 域名 方式查看HTTP协议版本)。
2. 第一字节时间过久(TTFB)
- 服务器生成页面数据时间过久
- 网络原因
- 发送请求头带上了多余的用户信息:比如不必要的Cookie信息
3.ContentLoad时间过久
可能是字节数太多的原因导致的。这时候你就需要减少文件大小,比如压缩、去掉源码中不必要的注释等方法。
22 | DOM树:JavaScript是如何影响DOM树构建的
什么是DOM
网络传递给渲染引擎的HTML文件字节流渲染引擎是无法理解,需要将其转换为其能够理解的内部结构,这个内部结构就是DOM,DOM提供了对HTML文档结构化的表述,主要作用有三种:
- DOM是生成页面的基础数据结构
- DOM提供给JS脚本操作DOM的接口
- DOM是一道安全防线,不安全内容在DOM解析阶段会被拒之门外。
DOM树如何生成
简言之:通过HTML解析器,将HTML字节流转换为DOM结构。
- 阶段一:通过分词器将字节流转换为Token。
- 阶段二、阶段三同步进行,将Token解析为DOM节点,并将DOM节点添加到DOM树中。
JavaScript是如何影响DOM生成的
- 一段HTML文件,如果加入了script标签(内有脚本内容),在解析到此script标签时,此时的HTML解析器会暂停DOM的解析,因为接下来JavaScript可能要修改当前生成的DOM结构。
- 如果HTML文件中通过script引入了js文件,那解析到script时,需要先下载这段JS代码,而下载过程会阻塞DOM接续,因此一方面浏览器做了预解析的操作优化,而另一方面对我们来说,如果该scipt标签内没有操作DOM的相关代码,可以将该脚本设置为异步加载(async或defer)。
async与defer的区别是:async方法在脚本文件下载完毕后立即执行。而defer是在DOMContentLoaded事件之前执行。- JS引擎在解析JS之前,并不知道其中是否会有操纵CSSOM行为的代码,所以在解析JS前,不管是否操纵了CSSOM,都会先去下载CSS文件并解析成CSSOM后,才会再来执行JS脚本。
最后,得出结论,JavaScript会阻塞DOM的生成,而CSSOM又会阻塞JavaScript的执行,因此DOM的生成受到JS和CSS的影响。
23 | 渲染流水线:CSS如何影响首次加载时的白屏时间?
首先,在上一节基础上进行一个小扩展:Chrome浏览器的预解析线程会先对文件中扫描到的js或者css文件进行一个提前下载数据的阶段,然后这个阶段就可能会因为下载文件而造成阻塞。
然后,渲染流水线需要CSSOM是因为浏览器一样无法直接理解CSS,需要转换成CSSOM,然后进行样式计算、计算布局等阶段。
最后,渲染流水线的流程再简单梳理一遍就是:HTML解析器再接收到数据后,预解析器识别出了有CSS和JavaScript文件,会预先对这些资源进行同步下载,然后生成DOM之前,由于DOM受JS影响,而JS又受CSSOM影响,所以,首先保证的是CSS的下载完成、CSSOM的结构生成。
针对这个渲染流程的阶段分析,其白屏瓶颈为:下载CSS和JavaScipt以及执行JavaScript的时间,因此缩短白屏时长的策略有:
- 通过内敛CSS和JS文件,减少这两种文件的下载时间
- 减少文件大小,通过Webpack等工具移除不必要的注释、压缩JS文件等方式。
- 不需要在HTML阶段使用的JS标记async和defer。
- CSS文件过大,可通过媒体查询属性,标记为多个不同用途CSS文件,只在特定环境下加载特点CSS文件。
24 | 分层和合成机制:为什么CSS动画比JavaScript高效
显示器是怎么显示图像的
每个显示器都有固定的刷新频率,通常是60HZ,也就是每秒更新60张图片,更新的图片都来自显卡中一个叫做前缓冲区的地方,显示器的工作就是每秒固定读取60张从前缓冲区中的图像,显示在显示器上。
这个显卡的作用就是合成新的图片,将生成的图片保存在后缓冲区,然后与前缓冲区进行交换,其刷新频率和显示器一致。
帧和帧率
我们在滑动页面或者手势缩放页面的过程中,屏幕产生了相应的效果,这是因为滚动或者缩放的这个操作,渲染引擎迅速捕捉到这个动作并将60张图片更新到显卡的后缓冲区,然后显卡的后缓冲区与前缓冲区进行交换,显示器从显卡前缓冲区读取这个图像,显示在显示器上。
将渲染流水线生成的每一张图片称为一帧,每秒更新了多少帧称为帧率。
于是,要解决一帧生产时间过久的问题,Chrome对浏览器渲染方式做了大量工作,其中最卓有成效的就是引入了分层和合成机制。
生成一帧图像的方式
生产一帧的生成方式有重绘、重排、合成三种方式。
- 重排会重新根据CSSOM和DOM来计算布局树,生成一张图片会将整个渲染流水线都执行一遍。
- 重绘在生成一张图片的过程中,少了重新布局的阶段,但依然会进重新计算绘制消息,会比重排效率高。
- 合成不会触发布局和绘制过程,因此合成效率更高。
- 重排和重绘操作都是在渲染进程的主线程上执行的,比较耗时;而合成操作是在渲染进程的合成线程上执行的,执行速度快,且不占用主线程。
分层和合成
分层是将多个素材分解成多个图层处理,将这些图层合并在一起就叫做合成。
然后根据阶段一的内容,我们知道在(构建DOM树、样式计算、布局阶段) 后,就是分层的过程,之所以需要分层,是后续的流程需要根据这个层来干事情,比如再之后的绘制会对每一个层生成一个个绘制指令,然后光栅化阶段根据一个个指令生成图片,一个图层就是一张图片,最后合成线程就将一张张图片进行合成一张图片,将最终生成的图片发送至显卡的后缓冲区。
这就是分层和合成的流程。
需要特别注意的是:合成的这个操作是在合成线程中完成的,不会影响主线程执行。
分块
通常页面内容比显示器内容要大很多,若等待所有图片都生成完毕再通过和合成生成一张图片的话,开销会很大,因此合成线程会优先绘制靠近视口的图块,且在首次合成图块的时候使用了一个低分辨率的图片。等正常比例的网页内容绘制好之后,再替换掉当前显示的低分辨率内容。
利用分层技术优化代码
当对一些元素进行几何形状变换、透明度变换、缩放等操作时,使用JS操作会牵扯到整个渲染流水线,而使用CSS则只会经过合成线程的合成阶段,效率要大很多。
也就解释了为什么CSS动画要比JavaScript动画效率高。
25 | 页面性能:如何系统地优化页面
这里讨论的优化页面是指:如何更快的让页面显示和响应。
而页面的周期分为加载阶段、交互阶段和关闭阶段,前两个阶段是用户体验的主要阶段。
加载阶段
加载阶段也就是资源下载整合的阶段,这些资源包括图片、音频、视频等不会影响阻塞页面首次加载的资源,以及JS、CSS、HTML等阻塞首次渲染的资源。
阻塞首次渲染的资源称为关键资源,优化点有:
- 尽量减少关键资源个数
- 关键资源内容尽量小
- 降低关键资源的RTT次数。
交互阶段
- 减少JavaScript脚本执行时间
- 避免强制同步布局。
- 避免布局抖动
- 合理利用CSS合成动画
- 避免频繁的垃圾回收
26 | 虚拟DOM和实际DOM有何不同
DOM缺陷
DOM缺陷就是往往一个小的DOM操作,渲染引擎需要进行重排、重绘、合成等操作,这些操作非常频繁且耗时,会带来性能问题。
然后需要一种方式来减少JS对DOM的操作,于是虚拟DOM就来了。
什么是虚拟DOM
虚拟DOM的作用是:
- 将页面改变的内容应用到虚拟DOM上,不是直接应用到DOM上。
- 变换应用到虚拟DOM上时,不会着急去渲染页面,而仅是调整虚拟DOM的内部状态,这样操作虚拟DOM效率高且畅快。
- 虚拟DOM收集到足够的改变,将这些变化一次性应用到真实DOM上,这样就能较少一些不必要的更新,同时保证DOM稳定输出。
27 | 渐进式网页应用(PWA):它究竟解决了Web应用的哪些问题?
PWA:Progressive Web App 渐进式网页应用。
- PWA提供了一个渐进式的过渡方案,让Web应用逐步具有本地应用的能力,且根据技术的演进,采用渐进式的方式逐步支持各项新技术,不断实现本地应用特性,是一个非常缓和的渐进式策略,而不是一步到位。
- PWA是一种理念,渐进式增强Web的优势,通过技术手段渐进式缩短和本地应用或者小程序的距离,基于这套理念之下的技术都可以归类为PWA。
Web应用 VS 本地应用
相对于本地应用,Web应用缺少的是:
- 缺少离线使用能力。
- 缺少消息推送能力。
- 缺少一级入口。
当然,基于上面的这几种缺陷吧,PWA提供了两种解决防范:引入了Service Worker来尝试解决离线存储和消息推送的问题。
引入了manifest.json来解决一级入口的问题,可以让开发者定义桌面图标、显示名称、启动信息、页面主题颜色等。
Service Worker
主要思想是:在页面和网络直接增加一个拦截器,用来缓存和拦截请求。
这个拦截器是干嘛的呢:没有安装 Service Worker 之前,WebApp 都是直接通过网络模块来请求资源的。安装了 Service Worker 模块之后,WebApp 请求资源时,会先通过 Service Worker,让它判断是返回 Service Worker 缓存的资源还是重新去网络请求资源。一切的控制权都交由 Service Worker 来处理。
Web Worker
Web Worker是为了避免一个JS脚本执行占用主线程时间过长这个问题而出现的。
Web Worker是运行在页面主线程之外的,但Web Worker当中没有当前页面的DOM环境,因此只能执行和DOM无关的脚步,并通过postMessage方法将执行结果返回给主线程,也就是说,Web Worker是在渲染进程中开启的一个新线程。
然后Service Worker借鉴了Web Worker的核心思想:’让其运行在主线程之外’,而由于Web Worker是临时的,执行结果保存不下来,因此Service Worker增加了储存功能。
安全设计上,Service Worker采用HTTPS协议。
28 | WebComponent:像搭积木一样构建Web应用
怎么理解组件化呢:对内高内聚、对外低耦合。
阻碍前端组件化的因素
- CSS全局样式阻碍组件化
- DOM阻碍组件化,页面中只有一个DOM,任何地方都可以直接读取和修改DOM。
因此使用JS实现组件化没有问题,但是遇上CSS和DOM,就不好弄了。
WebComponent组件化
WebComponent给出的解决思路就是提供局部视图封装能力,让CSS和HTML和JS运行在局部环境,已使得不会影响全局。
他的实现简单概括为: 使用template属性来创建模板,使用影子DOM提供局部作用域,将template中DOM和CSS与全局进行隔离。
影子DOM
影子DOM的作用主要有两类:
- 影子DOM的元素对于整个网页是不可见的。
- 影子DOM的CSS不会影响到整个网页的CSSOM,影子内部的CSS只对内部元素起作用。