Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
258 lines (181 sloc) 9.57 KB

quicklink
npm gzip size downloads travis

quicklink

可以在空闲时间预获取页面可视区域(以下简称视区)内的链接,加快后续加载速度。

工作原理

Quicklink 通过以下方式加快后续页面的加载速度:

  • 检测视区中的链接(使用 Intersection Observer)。
  • 等待浏览器空闲(使用 requestIdleCallback)。
  • 确认用户并未处于慢速连接(使用 navigator.connection.effectiveType)或启用省流模式(使用 navigator.connection.saveData)。
  • 预获取视区内的 URL(使用 <link rel=prefetch> 或 XHR)。可根据请求优先级进行控制(若支持 fetch() 可进行切换)。

开发原因

该项目旨在为网站提供一套解决方案,预获取处于用户视区中的链接,同时保持极小的体积(minifiy/gzip 后 <1KB)。

安装方法

nodenpm 用户:

npm install --save quicklink

或者从 unpkg.com/quicklink 获取 quicklink

用法

初始化后,quicklink 将自动在闲时预获取视区内的链接 URL。

快速上手:

<!-- 从 dist 目录下引入 quicklink -->
<script src="dist/quicklink.js"></script>
<!-- 初始化(你可以随时进行) -->
<script>
quicklink();
</script>

举个例子,你可以在 load 方法触发之后进行初始化:

<script>
window.addEventListener('load', () =>{
   quicklink();
});
</script>

或者导入 ES 模块:

import quicklink from "dist/quicklink.mjs";
quicklink();

以上方法适用于多页网站。单页应用可以搭配 router 使用 quicklink:

  • 进入新路由地址后,调用 quicklink()
  • 针对特定 DOM 元素/组件调用 quicklink()
  • 调用 quicklink({urls:[...]}),传入自定义 URL 集合进行预获取。

API

quicklink 接受带有以下参数的 option 对象(可选):

  • el:指定需要预获取的 DOM 元素视区。
  • urls:预获取的静态 URL 数组(若此参数非空,则不会检测视区中 document 或 DOM 元素的链接)。
  • timeout:整型数,为 requestIdleCallback 设置超时。浏览器必须在此之前进行预获取(以毫秒为单位), 默认取 2 秒。
  • timeoutFn:指定超时处理函数。默认为 requestIdleCallback。也可以替换为 networkIdleCallback(详见 demo)等自定义函数。
  • priority:布尔值,指定 fetch 的优先级。默认为 false。若配置为 true 将会尝试使用 fetch() API(而非 rel=prefetch)。
  • origins: 静态字符串数组,包含允许进行预获取操作的 URL 主机名。默认为同域请求源,可阻止跨域请求。
  • ignores: RegExp(正则表达式),Function(函数)或者 Array(数组),用于进一步确定某 URL 是否可被预获取。会在匹配请求源之后执行。

待探索:

Polyfills

quicklink:

  • requestIdleCallback 的一个非常小的回退。
  • 需要支持 IntersectionObserver (请参阅 CanIUse)。我们推荐使用 Polyfill.io 等服务选择性地实现此功能:
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>

或者,请参见 Intersection Observer polyfill

方法

为预获取操作自定义超时时间

默认超时时间为 2 秒(通过 requestIdleCallback),这里我们重写为 4 秒:

quicklink({
  timeout: 4000
});

设置用于检测链接的 DOM 元素

默认值为 document

const elem = document.getElementById('carousel');
quicklink({
  el: elem
});

自定义预获取 URL 数组

如果你想指定用于预获取的静态 URL 列表,而不是视区内的链接,你可以使用自定义 URL。

quicklink({
   urls: ['2.html','3.html', '4.js']
});

为预获取设置请求优先级

默认为低优先级(rel=prefetch 或 XHR)。对于高优先级(priority: true)的操作,尝试使用 fetch() 或退阶使用 XHR。

quicklink({ priority: true });

自定义受允许请求源列表

指定可被预获取的主机名列表,默认情况下仅允许同源主机名。

划重点:你还得加上自己的主机名!

quicklink({
  origins: [
    // 添加我自己的
    'my-website.com',
    'api.my-website.com',
    // 添加第三方的
    'other-website.com',
    'example.com',
    // ...
  ]
});

允许所有源

允许所有跨域请求。

注意:可能会导致 CORB 以及 CORS 问题!

quicklink({
  origins: true,
  // 或者
  origins: []
});

自定义忽略模式

以下过滤器会在匹配 origin 之后执行。Ignores 在避免大型文件下载或 DOM 属性动态响应时十分有用!

// 默认启用同源限制。
//
// 这个示例会忽略所有对以下模式的请求:
//  - 所有 "/api/*" 路径名
//  - 所有 ".zip" 扩展名
//  - 所有带有 noprefetch 扩展名的 <a> 标签
//
quicklink({
  ignores: [
    /\/api\/?/,
    uri => uri.includes('.zip'),
    (uri, elem) => elem.hasAttribute('noprefetch')
  ]
});

也许你还想忽略那些包含 URL fragment 的 URL(比如 index.html#top),不对它们进行预获取。那么对于在页面中使用了锚点标题,或者在单页应用设置了 URL fragment 的情况,这个功能可以避免对类似的 URL 进行预获取。

使用 ignores 来实现:

quicklink({
    ignores: [
        uri => uri.includes('#')
        // 或者使用正则表达式: /#(.+)/
        // 或者使用元素匹配: (uri, elem) => !!elem.hash
    ]
});

浏览器支持

quicklink 提供的预获取是渐进增强的,跨浏览器支持如下:

  • 不使用 polyfills:Chrome,Firefox,Edge,Opera,Android Browser,Samsung Internet 支持。
  • 使用 Intersection Observer polyfill(gzipped/minified 后大约 6KB):Safari,IE9+ 支持。

部分功能支持分层实现:

直接使用预获取器

quicklink 包含一个预获取器,可以单独导入其他项目中。方法是先将 quicklink 作为依赖项安装,然后按如下方式使用:

<script type="module">
import prefetch from '../src/prefetch.mjs';

const urls = ['1.html', '2.html'];
const promises = urls.map(url => prefetch(url));
Promise.all(promises);
</script>

Demo

这个 WebPageTest demo 演示了 quicklink 的预获取功能,它将页面加载性能提高了 4 秒! 这个 Youtube 视频 对使用预获取之前和之后进行了对比。

为了做演示,我们在 Firebase 上部署了一个 Google Blog,接着部署了另一个在主页添加了 quicklink 的版本,测试从主页导航到一个自动预获取的文章所用时间。结果表明预获取版本加载速度更快。

请注意:这绝不是对这项技术优缺点的详尽测试,只是演示了该方法可能带来的潜在改进。你自己的实现可能不尽相同。

相关项目

  • 在用 Gatsby 吗? 现在可以免费下载它了。它使用 Intersection Observer 预获取视图中的所有链接,本项目灵感亦来源于此。
  • 想要更加数据驱动的方案吗? 参见 Guess.js。它根据用户上网方式,使用数据分析和机器学习来预获取资源。它还有 WebpackGatsby 的插件。

许可证

本项目已获得 Apache-2.0 许可。

You can’t perform that action at this time.