quicklink

quicklink

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

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

quicklink预取性能优化网页加载JavaScriptGithub开源项目
<p align="center"> <img src="https://yellow-cdn.veclightyear.com/835a84d5/effe6706-f03f-420a-8be6-77053bf524b0.png" alt="" width="640"> <br> <a href="https://www.npmjs.com/package/quicklink"> <img src="https://img.shields.io/npm/v/quicklink?style=flat&logo=npm&logoColor=fff" alt="npm"> </a> <a href="https://unpkg.com/quicklink"> <img src="https://img.shields.io/bundlephobia/minzip/quicklink" alt="gzip size"> </a> <a href="https://github.com/GoogleChromeLabs/quicklink/actions/workflows/ci.yml?query=workflow%3ACI+branch%3Amain"> <img src="https://img.shields.io/github/actions/workflow/status/GoogleChromeLabs/quicklink/ci.yml?branch=main&label=ci&logo=github" alt="ci"> </a> </p>

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 许可证 授权。

编辑推荐精选

TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
商汤小浣熊

商汤小浣熊

最强AI数据分析助手

小浣熊家族Raccoon,您的AI智能助手,致力于通过先进的人工智能技术,为用户提供高效、便捷的智能服务。无论是日常咨询还是专业问题解答,小浣熊都能以快速、准确的响应满足您的需求,让您的生活更加智能便捷。

imini AI

imini AI

像人一样思考的AI智能体

imini 是一款超级AI智能体,能根据人类指令,自主思考、自主完成、并且交付结果的AI智能体。

Keevx

Keevx

AI数字人视频创作平台

Keevx 一款开箱即用的AI数字人视频创作平台,广泛适用于电商广告、企业培训与社媒宣传,让全球企业与个人创作者无需拍摄剪辑,就能快速生成多语言、高质量的专业视频。

即梦AI

即梦AI

一站式AI创作平台

提供 AI 驱动的图片、视频生成及数字人等功能,助力创意创作

扣子-AI办公

扣子-AI办公

AI办公助手,复杂任务高效处理

AI办公助手,复杂任务高效处理。办公效率低?扣子空间AI助手支持播客生成、PPT制作、网页开发及报告写作,覆盖科研、商业、舆情等领域的专家Agent 7x24小时响应,生活工作无缝切换,提升50%效率!

蛙蛙写作

蛙蛙写作

AI小说写作助手,一站式润色、改写、扩写

蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。

AI辅助写作AI工具蛙蛙写作AI写作工具学术助手办公助手营销助手AI助手
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
下拉加载更多