Prefetch&Preload预加载方案总结

3,158 阅读4分钟

为了提高网页首次加载响应速度,对移动端预加载方案进行调研整理。

方案大体分为三类:

  • 浏览器机制 - prefetch & preload;
  • webpack魔法注释 - 通过魔法注释可以直接通过 webpack 实现 prefetch & preload;
  • 应用框架工具库 - 因为我们是 react 技术栈故选择 react-loadable;

prefetch

prefetch是一种浏览器机制,其利用浏览器空闲时间来下载或预取用户在不久的将来可能访问的文档。网页向浏览器提供一组预取提示,并在浏览器完成当前页面的加载后开始静默地拉取指定的文档并将其存储在缓存中。当用户访问其中一个预取文档时,便可以快速的从浏览器缓存中得到。

<link rel="prefetch" href="/images/big.jpeg">

Can I use

preload

<link> 元素的 rel 属性的属性值preload能够让你在你的HTML页面中 <head>元素内部书写一些声明式的资源获取请求,可以指明哪些资源是在页面加载完成后即刻需要的。对于这种即刻需要的资源,你可能希望在页面加载的生命周期的早期阶段就开始获取,在浏览器的主渲染机制介入前就进行预加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。本文提供了一个如何有效使用preload机制的基本说明。

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

Can I use

prefetch & preload 小结

上文主要截取了MDN上的文章简要介绍一下prefetch和preload的特性,看起来其实都还不错但是兼容性有些堪忧对于多数的业务开发看起来是并不能投入使用的,如果想了解更多关于 prefetch和 preload 的细节可以阅读文章底部的参考链接。

webpack对prefetch 和 preload的支持

现在大多数人都是使用webpack做为构建工具,如果你所参与的项目只需要兼容较高的版本的浏览器,那么你可以轻松的依靠webpack 完成预加载功能,webpack 魔法注释就可以完成向引用的页面自动添加 preload & prefetch link 标签的能力。

webpack 魔法注释

通过添加内联的注释赋予import()动态加载语法更多实用的特性,比如给chunk命名,使用不同的webpackMode,prefetch,preload 等。

import(
  /* webpackInclude: /\.json$/ */
  /* webpackExclude: /\.noimport\.json$/ */
  /* webpackChunkName: "my-chunk-name" */  `赋予 chunk 指定的名字`
  /* webpackMode: "lazy" */  `这个是默认值使用import()你什么也不加webpackMode就为 lazy`
  /* webpackPrefetch: true */ `赋予 chunk prefetch能力`
  /* webpackPreload: true */`赋予 chunk preload能力`
  `./locale/${language}`// 引用路径可以使用变量
);

webpack魔法注释占位符

在 webpack 2.6.0 支持俩个占位符[index][request]一个是自增id,一个是变量匹配的文件名。

import(/* webpackChunkName: "[request]" */ `../${component}/index`)//最终生成的chunkname就是对应组件的目录名称类似这种'_some-component_index-[hash].js`

react-loadable 预加载

react-loadable预加载跟webpack自动插入link标签的方式不同,它是在触发preload方法时直接将对应的script标签插入body下,下载完毕直接执行,好处就是这个不需要考虑兼容性稳稳的都可以,美中不足呢就是直接执行了js,不过影响不大,因为只是执行的异步组件的定义,而组件的生命周期函数并没有执行。(稍微解释一下为什么只执行定义而不执行生命周期,因为在使用异步加载组件必然都会配合react-router使用,所以在A页面预加载B但是并不会执行B生命周期函数)

// 官方DEMO
const LoadableBar = Loadable({
  loader: () => import('./Bar'),
  loading: Loading,
});

class MyComponent extends React.Component {
  state = { showBar: false };

  onClick = () => {
    this.setState({ showBar: true });
  };

  onMouseOver = () => {
    LoadableBar.preload();
  };

  render() {
    return (
      <div>
        <button
          onClick={this.onClick}
          onMouseOver={this.onMouseOver}>
          Show Bar
        </button>
        {this.state.showBar && <LoadableBar/>}
      </div>
    )
  }
}

总结

  • preload & prefetch 等等新标准看起来都很美好只是浏览器支持情况不是那么理想很难直接投入使用,网上介绍这些特性的文章蛮多的不过读的时候要注意时效性。

  • webpack 内置支持了preload & prefetch相信不久的将来通过webpack轻松的完成预加载会是最广泛简单的做法。

  • react-loadable 解决了当前的燃眉之急可以兼容低版本的浏览器作为项目预加载方案使用。

参考