页面加载过程详解和优化策略

Vi 2019-06-25

前言

页面加载过程详解和优化策略

通过HTML5 Performanc相关的API,我们可以对页面进行性能分析。

下面会就几个比较重要的过程进行分析,给出耗时计算方法,并针对性的给出一些优化建议。

// 下文中的timing均表示performance.timing
let timing = window.performance.timing;

DNS解析

域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。

简单来说就是将一个域名映射到其对应的服务器IP地址,后续的请求均发送到该服务器。

DNS查询的基本过程如下:

  1. 查找浏览器缓存
    浏览器会缓存DNS查询结果,不同的浏览器缓存时间会有所不同。如果浏览器存在缓存,那么DNS查询就到此为止。
  2. 查找系统缓存
    浏览器缓存中没有需要的数据时,就会往上找到操作系统缓存。我们也可以手动配置host文件,这样浏览器会优先使用我们的配置。
  3. 查找路由器缓存
    系统缓存中也没有需要的数据时,就会找到路由器。
  4. 查找运营商DNS缓存
    之后会向运营的服务器(网络配置中的DNS服务器地址)请求DNS数据。
  5. 递归搜索
    如果运营商服务器内也没有需要的数据时,就会开始消耗最大的递归搜索。

举个栗子m.taobao.com:

  1. 首先向根域名服务器请求顶级域com的IP地址;
  2. 获取返回值后,向顶级域com的服务器请求一级域名taobao的IP地址;
  3. 获取返回值后,向一级域名taobao的服务器请求二级域名m的IP地址;
  4. 获取返回值后,完成查找,返回m.taobao.com的IP地址;
    根据网络的不同,这一块的耗时可能高达十几秒。

耗时计算:

let dns = timing.domainLookupEnd - timing.domainLookupStart;

明白工作原理后我们就可以针对域名解析这块做出一些优化,下面是一些优化建议:

  1. 考虑到域名解析是有时间消耗的,而且有可能消耗还不小,所以我们可以减少页面中使用到的域名数量,从而减少解析次数;
  2. 另外一个方法是进行DNS预解析,提前解析好的域名地址会被缓存在浏览器中,对其他页面也能起到加速的作用;
  3. HttpDNS,减少时延的同时还能防劫持;

建立连接

页面加载过程详解和优化策略

耗时计算:

let tcp = timing.connectEnd - timing.connectStart;

优化点如下:

  1. 避免重定向,这个不解释;
  2. 适当的合并请求,同上,减少握手次数;
  3. 长链接keep-alive,同上,减少握手次数;

发送请求

从发送请求到开始响应的过程。
耗时计算:

let req = timing.responseStart - timing.requestStart;

优化点如下:

  1. 避免重定向,还是不解释;
  2. 减少请求数据量,检查是否存在冗余的cookie;
  3. 使用CDN,缩短传输链路;

接收数据

从响应开始到数据传输完成的过程。
耗时计算:

let res = timing.responseEnd - timing.responseStart;

优化点如下:

  1. 减小html代码体积,包括去冗余以及代码压缩;
  2. 传输过程开启Gzip,进一步压缩传输数据量;
  3. 使用CDN,缩短传输链路;

解析DOM树

页面加载过程详解和优化策略

耗时计算:

let dom = timing.domInteractive - timing.domLoading;

优化点如下:

  1. 简化DOM结构,删除多余节点,避免深层嵌套;
  2. 同步的js会阻塞解析过程,考虑对js进行分段加载,延迟加载;

网页加载完成

下载并执行拥有defer属性的脚本。
耗时计算:

let dom = timing.domInteractive - timing.domLoading;

这一块的优化点主要集中在js代码层次的优化。然鹅,js的优化值得写本书来好好念叨念叨,so,这里就不展开了,主要给几个点吧:

  1. 减少需要加载的文件数,合并代码;
  2. 减小变量调用链路,多次访问到的对象成员保存成局部变量;
  3. 缓存函数运行结果;
  4. 算法优化,减少迭代次数,以及迭代的工作量;
  5. 缩短函数调用链;

DOM加载完成

DOM和CSSOM解析完成,并组合成为渲染树之后开始加载并执行defer的脚本。

defer的脚本执行完成就触发了DOMContentLoad事件,同时进行的还有图片,css等,这些资源文件加载完成后才是domComplete

domComplete之后就立刻触发load事件。
耗时计算

let domComplete = timing.domComplete - timing.domContentLoadedEventEnd;

这一块的优化主要集中在资源层次的优化,这也是一个比较大的项目,一样,挑几个点说一下:

  1. 使用css,iconfont,svg代替图片
  2. 根据屏幕分辨率进行适配
  3. 使用合适的图片格式,兼容的情况下,webp是个不错的选择
  4. 小图片使用data url代替
  5. 资源prefetch
  6. lazyload

此外,DOMContentLoaded事件耗时DOMLoad事件耗时,主要就是执行js代码,优化建议参考网页加载完成

以上~

相关推荐