21 | Chrome开发者工具:利用网络面板做性能分析


页面是浏览器的核心,浏览器中的所有功能都是服务于页面的,Chrome开发者工具又是调试页面的核心工具。

网络面板

  1. 控制器
  • 开始或停止抓包
  • 全局搜索
  • 禁止从cache中加载资源
  • 模拟网络
  1. 过滤器
  2. 抓图信息:Capture screenshots
  3. 详细列表:本节重点内容
  4. 下载信息概要
  • 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的时间,因此缩短白屏时长的策略有:

  1. 通过内敛CSS和JS文件,减少这两种文件的下载时间
  2. 减少文件大小,通过Webpack等工具移除不必要的注释、压缩JS文件等方式。
  3. 不需要在HTML阶段使用的JS标记async和defer
  4. CSS文件过大,可通过媒体查询属性,标记为多个不同用途CSS文件,只在特定环境下加载特点CSS文件。

24 | 分层和合成机制:为什么CSS动画比JavaScript高效


显示器是怎么显示图像的

每个显示器都有固定的刷新频率,通常是60HZ,也就是每秒更新60张图片,更新的图片都来自显卡中一个叫做前缓冲区的地方,显示器的工作就是每秒固定读取60张从前缓冲区中的图像,显示在显示器上。
这个显卡的作用就是合成新的图片,将生成的图片保存在后缓冲区,然后与前缓冲区进行交换,其刷新频率和显示器一致。

帧和帧率

我们在滑动页面或者手势缩放页面的过程中,屏幕产生了相应的效果,这是因为滚动或者缩放的这个操作,渲染引擎迅速捕捉到这个动作并将60张图片更新到显卡的后缓冲区,然后显卡的后缓冲区与前缓冲区进行交换,显示器从显卡前缓冲区读取这个图像,显示在显示器上。
将渲染流水线生成的每一张图片称为一帧,每秒更新了多少帧称为帧率
于是,要解决一帧生产时间过久的问题,Chrome对浏览器渲染方式做了大量工作,其中最卓有成效的就是引入了分层合成机制

生成一帧图像的方式

生产一帧的生成方式有重绘重排合成三种方式。

  • 重排会重新根据CSSOM和DOM来计算布局树,生成一张图片会将整个渲染流水线都执行一遍。
  • 重绘在生成一张图片的过程中,少了重新布局的阶段,但依然会进重新计算绘制消息,会比重排效率高。
  • 合成不会触发布局和绘制过程,因此合成效率更高。
  • 重排和重绘操作都是在渲染进程的主线程上执行的,比较耗时;而合成操作是在渲染进程的合成线程上执行的,执行速度快,且不占用主线程。

分层和合成

分层是将多个素材分解成多个图层处理,将这些图层合并在一起就叫做合成。
然后根据阶段一的内容,我们知道在(构建DOM树、样式计算、布局阶段) 后,就是分层的过程,之所以需要分层,是后续的流程需要根据这个层来干事情,比如再之后的绘制会对每一个层生成一个个绘制指令,然后光栅化阶段根据一个个指令生成图片,一个图层就是一张图片,最后合成线程就将一张张图片进行合成一张图片,将最终生成的图片发送至显卡的后缓冲区。
这就是分层和合成的流程。
需要特别注意的是:合成的这个操作是在合成线程中完成的,不会影响主线程执行

分块

通常页面内容比显示器内容要大很多,若等待所有图片都生成完毕再通过和合成生成一张图片的话,开销会很大,因此合成线程会优先绘制靠近视口的图块,且在首次合成图块的时候使用了一个低分辨率的图片。等正常比例的网页内容绘制好之后,再替换掉当前显示的低分辨率内容。

利用分层技术优化代码

当对一些元素进行几何形状变换、透明度变换、缩放等操作时,使用JS操作会牵扯到整个渲染流水线,而使用CSS则只会经过合成线程的合成阶段,效率要大很多。
也就解释了为什么CSS动画要比JavaScript动画效率高

25 | 页面性能:如何系统地优化页面


这里讨论的优化页面是指:如何更快的让页面显示和响应。
而页面的周期分为加载阶段、交互阶段和关闭阶段,前两个阶段是用户体验的主要阶段。

加载阶段

加载阶段也就是资源下载整合的阶段,这些资源包括图片、音频、视频等不会影响阻塞页面首次加载的资源,以及JS、CSS、HTML等阻塞首次渲染的资源。
阻塞首次渲染的资源称为关键资源,优化点有:

  1. 尽量减少关键资源个数
  2. 关键资源内容尽量小
  3. 降低关键资源的RTT次数。

交互阶段

  1. 减少JavaScript脚本执行时间
  2. 避免强制同步布局。
  3. 避免布局抖动
  4. 合理利用CSS合成动画
  5. 避免频繁的垃圾回收

26 | 虚拟DOM和实际DOM有何不同


DOM缺陷

DOM缺陷就是往往一个小的DOM操作,渲染引擎需要进行重排、重绘、合成等操作,这些操作非常频繁耗时,会带来性能问题。
然后需要一种方式来减少JS对DOM的操作,于是虚拟DOM就来了。

什么是虚拟DOM

虚拟DOM的作用是:

  1. 将页面改变的内容应用到虚拟DOM上,不是直接应用到DOM上。
  2. 变换应用到虚拟DOM上时,不会着急去渲染页面,而仅是调整虚拟DOM的内部状态,这样操作虚拟DOM效率高且畅快。
  3. 虚拟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只对内部元素起作用。