现代浏览器性能优化-JS篇

众所周知,JS的加载和执行会阻塞浏览器渲染,所以目前业界普遍推荐把script放到</body>之前,以解决js执行时找不到dom等问题。但随着现代浏览器的普及,浏览器为我们提供了更多强大的武器,合理利用,方可大幅提高页面加载速度。

理解渲染过程(HTML Parser)

首先我们从浏览器的角度解释一下从输入URL到页面展示经历了些什么,以如下html文档举例

<html>
<head>
<link rel="stylesheet" type="text/css" href="/style.css">
<script type="text/javascript" src="/header.js"></script>
</head>
<body>
<p>Text</p>
<script type="text/javascript" src="/main.js"></script>
</body>
</html>

浏览器自上而下读取html文档(此过程叫html parser),当发现style.css文件时,浏览器parser停下来去搞css,等style.css下载并解析完毕,浏览器继续parser。紧接着发现header.js, 于是html parser又停了,浏览器下载并执行完header.js,继续parser。此时屏幕上还什么都没有。...parser,发现<p>,遂将p中文字展示了出来。紧接着又发现main.js,浏览器又停下parser,下载并执行完main.js才继续parser,直到页面渲染完毕。

我们假设header.js中只有一行代码console.log('header'), 但服务器响应很慢,要10秒才能把它返回给浏览器,浏览器执行这段代码需要1ms,那在这 10s+1ms 内,页面将一直空白。浏览器执行JS的时间取决于代码质量和硬件,并不是前端工程师随便可以优化的,所以优化的重点在JS的下载时间。

核心:减少JS下载时间

预先解析DNS

非常简单,效果立竿见影,加快页面加载时间,多用于预解析CDN的地址的DNS

<!--在head标签中,越早越好-->
<link rel="dns-prefetch" href="//example.com">

Preload

浏览器会在遇到如下link标签时,立刻开始下载main.js(不阻塞parser),并放在内存中,但不会执行其中的JS语句。
只有当遇到script标签加载的也是main.js的时候,浏览器才会直接将预先加载的JS执行掉。

<link rel="preload" href="/main.js" as="script">

Prefetch

浏览器会在空闲的时候,下载main.js, 并缓存到disk。当有页面使用的时候,直接从disk缓存中读取。其实就是把决定是否和什么时间加载这个资源的决定权交给浏览器。

如果prefetch还没下载完之前,浏览器发现script标签也引用了同样的资源,浏览器会再次发起请求,这样会严重影响性能的,加载了两次,,所以不要在当前页面马上就要用的资源上用prefetch,要用preload。

<link href="main.js" rel="prefetch">

JS在什么时候执行的(defer和async)

上面我们的例子中,script标签都是在没有多余属性的情况下执行的,只要下载过程结束,浏览器就会将JS执行掉。
defer和async是script标签的两个属性,用于在不阻塞页面文档解析的前提下,控制脚本的下载和执行。

defer,async与下载时机也有关,具体看这张图。

defer的执行时间是在所有元素解析完成之后,DOMContentLoaded 事件触发之前。

async的执行时间是在当前JS脚本下载完成后,所以多个async script是执行顺序是不固定的。async只能用于加载一些独立无依赖的代码,比如Google Analysis之类。

完美的结构

前面两节帮我们弄懂了JS的下载和执行时机,那什么样的页面才是完美符合现代浏览器的那?其实关键在于的preload和prefetch!提前告知浏览器,我们的网站马上要用的是什么,以后可能要用的是什么,浏览器才能更快的渲染页面。下面是一段实例代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Faster</title>
<link rel="dns-prefetch" href="//cdn.com/">
<link rel="preload" href="//js.cdn.com/currentPage-part1.js" as="script">
<link rel="preload" href="//js.cdn.com/currentPage-part2.js" as="script">
<link rel="preload" href="//js.cdn.com/currentPage-part3.js" as="script"> <link rel="prefetch" href="//js.cdn.com/prefetch.js">
</head>
<body> <script type="text/javascript" src="//js.cdn.com/currentPage-part1.js" defer></script>
<script type="text/javascript" src="//js.cdn.com/currentPage-part2.js" defer></script>
<script type="text/javascript" src="//js.cdn.com/currentPage-part3.js" defer></script>
</body>
</html>

首先,Parser在遇到head中preload时开始下载JS,读到script标签的时候,如果已经下载完了,直接按顺序执行之。如果没下载完,则会等到下载完再执行。这样就可以在刚进入页面时开始非阻塞的下载JS代码了。

其次,页面会在空闲时,加载prefetch的JS,如果之后页面发生跳转,跳转的目标页面引入了prefetch.js,浏览器会直接从disk缓存中读取执行。

将script标签依然放在</body>之前,并增加defer标签,确保老浏览器兼容,并在所有DOM元素解析完成之后执行其中的代码。

至此,完美的HTML结构出炉了。

CSS的下载和解析一样会阻塞渲染,造成白屏,CSS中的字体文件更是影响首屏渲染关键因素之一,下一篇幅我会结合preload和prefetch,带你一起优化CSS,告诉你什么是最适合现代浏览器的CSS加载策略,期待的话,点个赞吧!

本文转载于:猿2048⇛https://www.mk2048.com/blog/blog.php?id=haabcc1k10j

带你玩转prefetch, preload, dns-prefetch,defer和async的更多相关文章

  1. Preload,Prefetch 和它们在 Chrome 之中的优先级

    前言 上周五到的时候,想起之前在手游平台上有处理dns-prefetch的优化,那这篇分享的就更仔细了.今日早读文章由@gy134340翻译并授权分享. 正文从这开始- 今天我们来深入研究一下 Chr ...

  2. Web 性能优化:Preload与Prefetch的使用及在 Chrome 中的优先级

    摘要: 理解Preload与Prefetch. 原文:Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级 作者:前端小智 Fundebug经授权转载,版权归原作者所 ...

  3. prefetch & preload & prerender & dns-prefetch & preconnect

    prefetch & preload & prerender & dns-prefetch & preconnect performance optimization ...

  4. DNS Prefetch

    DNS 实现域名到IP的映射.通过域名访问站点,每次请求都要做DNS解析.目前每次DNS解析,通常在200ms以下.针对DNS解析耗时问题,一些浏览器通过DNS Prefetch 来提高访问的流畅性. ...

  5. DNS Prefetch初认识

    今天在看一个后台框架时,发现这样的代码: <link rel="dns-prefetch" href="//0.s3.envato.com">< ...

  6. 浏览器 DNS缓存与DNS prefetch (DNS预解析)

    浏览器 DNS缓存 浏览器DNS缓存的时间跟DNS服务器返回的TTL值无关. 注:TTL(Time-To-Live),就是一条域名解析记录在DNS服务器中的存留时间. 浏览器在获取网站域名的实际IP地 ...

  7. DNS Prefetch 【DNS 预解析技术】

    DNS 实现域名到IP的映射.通过域名访问站点,每次请求都要做DNS解析.目前每次DNS解析,通常在200ms以下.针对DNS解析耗时问题,一些浏览器通过DNS Prefetch 来提高访问的流畅性. ...

  8. [PWA] Optimize Assets Delivery using preload and prefetch

    By default, browsers load the assets in a render-blocking way. Modern browsers introduced prefetch a ...

  9. preload、prefetch的认识

    预加载 现在的网络情况虽然很乐观,但是 defer和async 当浏览器碰到 script 脚本的时候: <script src="script.js"></sc ...

随机推荐

  1. Qt:QDateTime

    0.说明 提供时间日期的表达和相关函数. QDateTime通过日期+时间来构造一个日期时间.它综合了QDate和QTime的所有特性. 它可以通过系统时钟来获取当前DateTime.它还提供了比较时 ...

  2. HBase常用shell操作

    行(row),列(Column),列蔟(Column Family),列标识符(Column Qualifier)和单元格(Cell) 行:由一个个行键(rowkey)和一个多个列组成.其中rowke ...

  3. AC+AP组网无线WiFi网速超慢延迟卡顿问题解决

    AP是什么? AP是Access Point的简称,即无线接入点,其作用是把局域网里通过双绞线传输的有线信号(即电信号)经过编译,转换成无线电信号传递给电脑.手机等无线终端,与此同时,又把这些无线终端 ...

  4. 你真的懂TSP吗

    ​整数规划-模型 2022年2月26日 TSP问题 有一个邮递员,他每天负责向100个客户的家门口送一份报纸,他希望走最短的总路程来完成配送任务,这是TSP问题最原始的场景.用理论描述就是:找一个路径 ...

  5. LGP7884题解

    是的,这是一篇使用 min25 筛的题解... 本题解参考command_block大佬的博客,代码是对其在 LOJ 上的提交卡常后写出来的. ML 板子把数据开到 \(10^{13}\) 速度还和供 ...

  6. VuePress 博客之 SEO 优化(二)重定向

    前言 在 <一篇带你用 VuePress + Github Pages 搭建博客>中,我们使用 VuePress 搭建了一个博客,最终的效果查看:TypeScript 中文文档. 本篇讲讲 ...

  7. vue 通信:父子通信、兄弟通信、跨多层通信、vuex状态管理

    之前简单做了一次vue通信方法的培训,在此记录一下培训的内容. 关于vue通信,大家最先想到的方法应该是props.ref.$emit.$parent,还有vuex,因为这也是我在项目中最常用到的方法 ...

  8. 谈谈 Kubernetes Operator

    简介 你可能听过Kubernetes中Operator的概念,Operator可以帮助我们扩展Kubernetes功能,包括管理任何有状态应用程序.我们看到了它被用于有状态基础设施应用程序的许多可能性 ...

  9. python3生成一个含有20个随机数的列表,要求所有元素不相同,并且每个元素的值介于1到100之间

    import random alist = random.sample(range(1,101),20) #random.sample()生成不相同的随机数 print(alist)

  10. GO后端开发+VUE实列

    因为我是从java转到go,代码结构跟我之前用java的很像 在这里只浅显的实战运用,没有过多理论讲解 工作环境:IDE:Goland , Go 1.17.7 框架 Gin+Gorm ,前端VUE 这 ...