浅谈异步加载(defer、async、module)和预加载(preload、prefetch、subresource、prerender)前端文件

版权声明: https://blog.csdn.net/huangpb123/article/details/84170557

异步加载 js 文件

<script src="script.js"></script>

以上写法是平常常用的写法,浏览器遇到该 script 脚本会立即加载并执行此脚本,是一个同步的过程。

有时候我们想让 script 脚本异步加载,那要怎么处理呢?

只要在 script 标签上加上 defer 或 async 属性即可。

<script async src="script.js"></script>
<script defer src="script.js"></script>

defer 和 async 机制都是异步(相较于 HTML 解析)加载 js 脚本,但 js 脚本的执行时间还是有所区别的:

  • 有 defer,js 脚本异步加载,但是 js 脚本的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。而且是按照 defer 脚本的声明顺序来执行脚本的。
  • 有 async,js 脚本异步加载,加载完以后立马执行(异步)。

加载 ES6 模块

<script type="module" src="foo.js"></script>

<script> 标签加入 type="module" 属性,可以让浏览器异步加载 ES6 模块,不会造成阻塞,即等到整个页面渲染完,再执行模块脚本,等同于 <script> 标签加入 defer 属性。

<script type="module" src="foo.js"></script>
<!-- 等同于 -->
<script type="module" src="foo.js" defer></script>

当然,如有需要你也可以换成 async 属性。

<script type="module" src="foo.js" async></script>

ES6 模块也允许内嵌在网页中,语法与加载外部脚本完全一致。

<script type="module">
  import utils from "./utils.js";

  // other code
</script>

对于外部的 ES6 模块脚本,有几点需要注意:

  • 代码是在模块作用域中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。
  • 模块脚本自动采用严格模式,不管有没有声明 use strict。
  • 模块中,可以使用 import 加载其他模块(.js 后缀不可省略),也可以使用 export 输出对外接口。
  • 模块中,顶层的 this 关键字返回 undefined,而不是指向 window。
  • 同一个模块如果加载多次,将只执行一次。

预加载文件

说到预加载,我们会立马想到 preload、prefetch、subresource、prerender。

现在我们来讲讲这几个的用法和区别。

preload 和 prefetch

preload

使用 preload 可以对当前页面所需的脚本、样式等资源进行预加载,而无需等到解析到 script 和 link 标签时才进行加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。

使用方式:

将 link 标签的 rel 属性的值设为 preload,as 属性的值为资源类型(如脚本为 script,样式表为 style)。

<head>
   <meta charset="utf-8"/>
   <title>preload example</title>
   <!-- 对 style.css 和 index.js 进行预加载 -->
   <link rel="preload" href="style.css" as="style"/>
   <link rel="preload" href="index.js" as="script"/>
</head>

prefetch

prefetch 和 preload 一样,都是对资源进行预加载,但是 prefetch 一般预加载的是其他页面会用到的资源。

当然,prefetch 不会像 preload 一样,在页面渲染的时候加载资源,而是利用浏览器空闲时间来下载。当进入下一页面,就可直接从 disk cache 里面取,既不影响当前页面的渲染,又提高了其他页面加载渲染的速度。

使用方式:

同 preload 类似,无需指定 as 属性。

<head>
   <!-- 对资源进行 prefetch 预加载 -->
   <link rel="prefetch" href="next.css" />
   <link rel="prefetch" href="next.js" />
</head>

总结:对当前页面需要的资源,使用 preload 进行预加载。对其它页面需要的资源进行 prefetch 预加载。

subresource 和 prerender

subresource

subresource 可以用来指定资源是当前页面资源的最高优先级,如果资源买上就会用到,推荐使用 subresource。

使用方式:

<link rel="subresource" href="styles.css">

prerender

prerender 是一个重量级的选项,它可以让浏览器提前加载指定页面的所有资源。

使用方式:

<link rel="prerender" href="/thenextpage.html" />

prerender 就像是在后台打开了一个隐藏的 tab,会下载所有的资源、创建DOM、渲染页面、执行js等等。如果用户进入指定的链接,隐藏的这个页面就会立马进入用户的视线。

但是要注意,一定要在十分确定用户会点击某个链接时才使用该特性,否则客户端会无端的下载很多资源和渲染这个页面。

正如任何提前动作一样,预判总是有一定风险出错。如果提前的动作是昂贵的(比如高CPU、耗电、占用带宽),就要谨慎使用了。

可以利用 Page Visibility API 来防止页面在还没真正展示给用户时就触发了 js 的执行。

猜你喜欢

转载自blog.csdn.net/huangpb123/article/details/84170557