现代浏览器性能优化-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. Docker入坑系列(一)

    Docker入坑系列(一) 引用嘛,当然是来引用别人说的东西啦. Docker 是一个开源项目,诞生于 2013 年初,它基于 Google 公司推出的 Go 语言实现. 项目后来加入了 Linux ...

  2. kubernetes配置使用ceph动态存储

    在k8s集群中配置ceph 3.1.使用cephfs (1) 在ceph集群创建cephfs #以下操作在ceph集群的admin或者mon节点上执行 #创建pool来存储数据和元数据 ceph os ...

  3. git for windows下载

    https://npm.taobao.org/mirrors/git-for-windows/ 国内的镜像 转载自:https://blog.csdn.net/ee230/article/detail ...

  4. Python第一讲以及计算机基础

    本周课程安排 python基础(五天) 下周课程安排 tableau图形化表制作 下下周课程安排 spss 今日内容概要 计算机发展史 计算机主要硬件 编程与编程语言 python解释器及IDE编辑器 ...

  5. JZ-001-二维数组中的查找

    二维数组中的查找 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数 ...

  6. ORACLE中ROWNUM

    一.rownum 1.rownum是对结果集添加的一个伪列: 2.是先按某种条件查询出结果集之后又添加上的一个列; 3.它总是从1开始,因此在使用的过程中需要谨慎使用>,>=,=,betw ...

  7. C#-使用Newtonsoft.Json实现json字符串与object对象互转

    json字符串转object对象: IF004Response processResponse = JsonConvert.DeserializeObject<IF004Response> ...

  8. 调用Visual Studio的cl.exe编译C/C++程序

    @ 目录 调用Visual Studio的cl.exe编译C/C++程序 前言 1.查看VS的路径 2.添加环境变量 3.查看设置是否生效 4.配置Notepad++ 调用Visual Studio的 ...

  9. laravel7 webuploader上传图片

    webuploader上传 前提工作: 1>了解 代码如下:1.app_path() app_path函数返回app目录的绝对路径: $path = app_path(); 你还可以使用app_ ...

  10. tensorflow源码解析之framework-resource

    目录 什么是resource 如何使用resource 如何管理resource 常用resource 其它结构 关系图 涉及的文件 迭代记录 1. 什么是resource 我们知道,TF的计算是由设 ...