Project Icon

quicklink

智能预取技术加速网页加载的轻量级库

quicklink 是一个智能预取库,用于优化网页加载性能。它自动检测视口中的链接,并在浏览器空闲时预取或预渲染,提高后续页面访问速度。适用于多页面和单页面应用,提供灵活的配置选项。quicklink 代码精简,压缩后仅 2KB,是一个高效的开源性能优化工具。


npm gzip size ci

quicklink

通过在空闲时间预取或预渲染视口内的链接,实现后续页面加载更快

工作原理

Quicklink 试图使导航到后续页面的加载速度更快。它:

  • 检测视口内的链接(使用Intersection Observer
  • 等待浏览器空闲(使用requestIdleCallback
  • 检查用户是否处于慢速连接(使用navigator.connection.effectiveType)或启用了数据保护(使用navigator.connection.saveData
  • 预取(使用<link rel=prefetch>或XHR)或预渲染(使用Speculation Rules API)链接的URL。提供一些对请求优先级的控制(如果支持,可以切换到fetch())。

为什么

这个项目旨在为网站提供一个即插即用的解决方案,根据用户视口中的内容预取或预渲染链接。它还致力于保持小巧(压缩并gzip后小于2KB)。

多页应用

安装

对于Node.jsnpm

npm install quicklink

你也可以从unpkg.com/quicklink获取quicklink

使用

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

快速开始:

<!-- 从dist引入quicklink -->
<script src="dist/quicklink.umd.js"></script>
<!-- 初始化(你可以在任何时候进行) -->
<script>
  quicklink.listen();
</script>

例如,你可以在load事件触发后初始化:

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

ES模块导入:

import {listen, prefetch} from 'quicklink';

单页应用(React)

安装

首先,使用Node.jsnpm安装包:

npm install quicklink webpack-route-manifest --save-dev

然后,按照这里的说明将Webpack路由清单配置到你的项目中。 这将生成一个名为rmanifest.json的路由和代码块映射。可以在以下位置获取:

  • URL:site_url/rmanifest.json
  • Window对象:window.__rmanifest

使用

在你想添加预取功能的地方导入quicklink React HOC。 用withQuicklink()HOC包装你的路由。

例子:

import {withQuicklink} from 'quicklink/dist/react/hoc.js';

const options = {
  origins: [],
};

<Suspense fallback={<div>加载中...</div>}>
  <Route path='/' exact component={withQuicklink(Home, options)} />
  <Route path='/blog' exact component={withQuicklink(Blog, options)} />
  <Route path='/blog/:title' component={withQuicklink(Article, options)} />
  <Route path='/about' exact component={withQuicklink(About, options)} />
</Suspense>;

API

quicklink.listen(options)

返回:Function

返回一个"重置"函数,该函数将清空活动的IntersectionObserver和已预取或预渲染的URL缓存。这可以在页面导航之间和/或发生重大DOM更改时使用。

options.prerender

  • 类型:Boolean
  • 默认值:false

是否从默认的预取模式切换到视口内链接的预渲染模式。

**注意:**当浏览器不支持预渲染时,预渲染模式(当此选项设置为true时)将回退到预取模式。

options.prerenderAndPrefetch

  • 类型:Boolean
  • 默认值:false

是否同时激活预取和预渲染模式。

options.delay

  • 类型:Number
  • 默认值:0

每个链接在被预取之前需要停留在视口内的时间,以毫秒为单位。

options.el

  • 类型:HTMLElement|NodeList<A>
  • 默认值:document.body

要观察的DOM元素,用于检测视口内需要预取的链接,或锚点元素的NodeList。

options.limit

  • 类型:Number
  • 默认值:Infinity

在观察options.el容器时可以预取或预渲染的总请求数。

options.threshold

  • 类型:Number
  • 默认值:0

每个链接必须进入视口的面积百分比才能被获取,以小数形式表示(例如,0.25 = 25%)。

options.throttle

  • 类型:Number
  • 默认值:Infinity

在观察options.el容器时,同时进行的请求数限制。

options.timeout

  • 类型:Number
  • 默认值:2000

requestIdleCallback超时时间,以毫秒为单位。

**注意:**浏览器必须在配置的持续时间内保持空闲状态才会进行预取。

options.timeoutFn

  • 类型:Function
  • 默认值:requestIdleCallback

用于指定timeout延迟的函数。

这可以替换为自定义函数,如networkIdleCallback(参见演示)。

默认情况下,使用requestIdleCallback或嵌入的polyfill。

options.priority

  • 类型:Boolean
  • 默认值:false

options.el容器内的URL是否应被视为高优先级。

当设置为true时,如果支持,quicklink将尝试使用fetch() API(而不是link[rel=prefetch])。

options.origins

  • 类型:Array<String>
  • 默认值:[location.hostname]

允许预取的URL主机名的静态数组。

默认为相同的域名源,这可以防止任何跨域请求。

重要:空数组([])允许预取所有来源

options.ignores

  • 类型:RegExpFunctionArray
  • 默认值:[]

确定是否应预取URL。

RegExp测试为正,Function返回true,或Array包含字符串时,则不会预取该URL。

注意:Array可以包含StringRegExpFunction值。

**重要:**此逻辑在源匹配之后执行!

options.onError

  • 类型:Function
  • 默认值:无

一个可选的错误处理函数,用于接收预取请求中的任何错误。

默认情况下,这些错误会被静默忽略。

options.hrefFn

  • 类型:Function
  • 默认值:无

一个可选函数,用于生成要预取的URL。它接收一个Element作为参数。

quicklink.prefetch(urls, isPriority)

返回:Promise

提供的urls始终通过Promise.all传递,这意味着结果将始终解析为一个数组。

**重要:**你必须自行catch请求错误。

urls

  • 类型:StringArray<String>
  • 必需:true

一个或多个要预取的URL。

**注意:**每个url值都是相对于当前位置解析的。

isPriority

  • 类型:Boolean
  • 默认值:false

是否将URL视为"高优先级"目标。

默认情况下,对prefetch()的调用为低优先级。

**注意:**这与listen()priority选项行为相同。

quicklink.prerender(urls)

返回:Promise

**重要:**你必须自行catch请求错误。

urls

  • 类型:StringArray<String>
  • 必需:true

一个或多个要预渲染的URL。

**注意:**推测性规则API支持同站跨域预渲染,需要选择加入头部

填充

quicklink

  • 包含一个非常小的requestIdleCallback回退
  • 需要支持IntersectionObserver(参见Can I Use)。我们建议使用Polyfill.io等服务有条件地填充此功能:
<script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver"></script>

或者,参见Intersection Observer polyfill

使用示例

为预取资源设置自定义超时

默认为2秒(通过requestIdleCallback)。这里我们将其覆盖为4秒:

quicklink.listen({
  timeout: 4000,
});

设置特定的锚元素NodeList以观察视口内的链接

默认为document

quicklink.listen({
  el: document.querySelectorAll('a.linksToPrefetch'),
});

设置DOM元素以观察视口内的链接

默认为document

quicklink.listen({
  el: document.getElementById('carousel'),
});

以编程方式prefetch() URL

如果你更喜欢提供一个静态的URL列表进行预取,而不是检测视口内的URL,支持自定义URL。

// 单个URL
quicklink.prefetch('2.html');

// 多个URL
quicklink.prefetch(['2.html', '3.html', '4.js']);

// 多个URL,高优先级
// 注意:也可用于单个URL!
quicklink.prefetch(['2.html', '3.html', '4.js'], true);

以编程方式prerender() URL

如果你更喜欢提供一个静态的URL列表进行预渲染,而不是检测视口内的URL,支持自定义URL。

// 单个URL
quicklink.prerender('2.html');

// 多个URL
quicklink.prerender(['2.html', '3.html', '4.js']);

设置滚动时预取的请求优先级

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

**注意:**这会在options.el容器内找到的URL上运行prefetch(..., true)

quicklink.listen({priority: true});

指定允许的源的自定义列表

提供应该可预取的主机名列表。默认情况下只允许相同源。

**重要:**你还必须包括你自己的主机名!

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

允许所有源

启用所有跨源请求。

**注意:**你可能会遇到CORBCORS问题!

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

自定义忽略模式

这些过滤器在origins匹配之后运行。忽略可用于避免大文件下载或动态响应DOM属性。

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

你可能还希望忽略包含URL片段的URL预取(例如index.html#top)。如果你(1)正在使用页面中的锚点标题或(2)为单页应用设置了URL片段,并希望避免为类似的URL触发预取,这可能很有用。

使用ignores可以实现如下:

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

通过hrefFn回调自定义要预取的URL

hrefFn方法允许动态构建要预取的URL(例如API端点),而不是预取href属性URL。

quicklink.listen({
  hrefFn(element) {
    return element.href.replace('html', 'json');
  },
});

浏览器支持

quicklink提供的预取可以视为渐进增强。跨浏览器支持如下:

  • 无需填充:Chrome、Safari ≥ 12.1、Firefox、Edge、Opera、Android Browser、Samsung Internet。
  • 使用Intersection Observer polyfill(约6KB gzip压缩/最小化):Safari ≤ 12.0、IE11
  • 使用上述填充以及Set()Array.from填充:IE9和IE10。Core.js提供了Set()Array.from()两种垫片。es6-shim等项目是你可以考虑的替代方案。

某些功能具有分层支持:

直接使用预取器

prefetch 方法可以单独导入以在其他项目中使用。

该方法包含了尊重数据节省模式和 2G 连接的逻辑。它还会根据 isPriority 值和当前浏览器的支持情况,通过 fetch()、XHR 或 link[rel=prefetch] 发出请求。

在将 quicklink 安装为依赖项后,你可以按以下方式使用它:

<script type="module">
  import {prefetch} from 'quicklink';
  prefetch(['1.html', '2.html']).catch(error => {
    // 处理自己的错误
  });
</script>

演示

Glitch 演示

研究

这是我们演示WebPageTest 运行结果,通过 quicklink 的预取功能将页面加载性能提高了最多 4 秒。YouTube 上有一个预取前后对比的视频

出于演示目的,我们在 Firebase 托管上部署了 Google Blog 的一个版本。然后我们部署了另一个版本,在主页上添加了 quicklink,并对从主页导航到自动预取的文章进行了基准测试。预取版本加载得更快。

请注意:这绝不是对视口内链接预取的优缺点的全面基准测试。只是展示了这种方法可能带来的潜在改进。你自己的实际效果可能会有很大差异。

其他说明

会话拼接

跨源预取(例如 a.com/foo.html 预取 b.com/bar.html)有许多限制。其中一个限制是会话拼接。b.com 可能期望 a.com 的导航请求包含会话信息(例如临时 ID - 如 b.com/bar.html?hash=<>&timestamp=<>),这些信息用于自定义体验或记录分析信息。如果会话拼接需要 URL 中的时间戳,预取并存储在 HTTP 缓存中的内容可能与用户最终导航到的内容不同。这带来了一个挑战,因为它可能导致双重预取。

为了解决这个问题,你可以考虑通过 ping 属性(单独)传递会话信息,以便源站可以异步拼接会话。

广告相关考虑

依赖广告作为收入来源的网站不应预取广告链接,以避免无意中计算这些广告位置的点击次数,这可能导致广告点击率(CTR)虚高。

广告主要以两种方式出现在网站上:

  • 在 iframe 内: 默认情况下,大多数广告服务器在 iframe 内渲染广告。在这些情况下,除非开发人员明确传入广告 iframe 的 URL,否则 Quicklink 不会预取这些广告链接。原因是库对视口内元素的查找仅限于顶级源的元素。

  • 在 iframe 外: 当网站显示同源广告,直接显示在顶级文档中(例如,自行托管广告并直接在页面中显示)时,开发人员需要明确告诉 Quicklink 避免预取这些链接。这可以通过将广告链接的 URL 或子路径,或包含它的元素传递给自定义忽略模式列表来实现。

相关项目

  • 使用 Gatsby?你已经免费获得了大部分这些功能。它使用 Intersection Observer 预取所有在视图中的链接,并为本项目提供了重要灵感。
  • 想要更加数据驱动的方法?看看 Guess.js。它使用分析和机器学习基于用户如何浏览你的网站来预取资源。它还有 WebpackGatsby 的插件。
  • WordPress 用户现在可以从插件库中获得 quicklink 作为 WordPress 插件
  • Drupal 用户可以安装 Quicklink Drupal 模块
  • Magento 2 用户可以安装 rafaelcg-magento2-quicklinkrangerz/magento2-module-quicklink
  • 想要不那么激进的预取?instant.page 在鼠标悬停和触摸开始时预取,就在点击之前。

许可证

根据 Apache-2.0 许可证 授权。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号