前端性能优化(prefetch, preload, dns-prefetch, defer, async)
常用方式:放到</body>之前,解决js运行时找不到dom的问题。
页面渲染过程(HTML parser)
<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>
- 从上到下parser
- 停止parser,下载并解析style.css
- parser
- 停止parser,下载并执行header.js
- parser, 展示 p
- 停止parser,下载并执行main.js
- parser to end
如果下载脚本很慢,会造成长时间空白。
一、减少JS下载时间(dns-prefetch, preload, prefetch)
预先解析DNS
用于预解析CDN地址的DNS
<!--在head标签中,越早越好--> <link rel="dns-prefetch" href="//dns.example.com">
preload (马上要用什么)
- 遇到link标签时,立刻下载并放到内存中,不执行js。
- 遇到script标签时,将预加载的js执行。
<link rel="preload" href="./main.js" as="script">
prefetch(以后可能要用什么)
- 浏览器空闲时,下载并缓存到disk
- 有页面使用时,从disk中读取
- 不要在当前页面马上要用的资源上用prefetch,要用preload(因为prefetch还没加载完成时,遇到script会再次发起请求,加载两次严重影响性能)
<link rel="prefetch" href="./main.js">
二、控制JS的执行时机(defer, async)
defer
所有元素解析完成后,DOMContentLoaded事件触发之前。
async
当前JS脚本加载完成后(加载后立即执行,执行顺序不固定,适合独立无依赖的代码)
三、完整过程
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="dns-prefetch" href="//cdn.com"> <link rel="preload" href="//cdn.com/js/currentPage-part1.js" as="script"> <link rel="preload" href="//cdn.com/js/currentPage-part2.js" as="script"> <link rel="preload" href="//cdn.com/js/currentPage-part3.js" as="script"> <link rel="prefetch" href="//cdn.com/js/otherPage.js"> </head> <body> <script src="//cdn.com/js/currentPage-part1.js" defer></script> <script src="//cdn.com/js/currentPage-part2.js" defer></script> <script src="//cdn.com/js/currentPage-part3.js" defer></script> </body> </html>