文档章节

谷歌开源quicklink,加载时间从4.6s降到0.7s

JamesView
 JamesView
发布于 01/25 17:55
字数 1541
阅读 97
收藏 0

 

作者|Google 团队

译者|无明

近日,Google 团队在 GitHub 上开源了一个项目 quicklink,quicklink 能在空闲时预取 viewport 内的链接来加快后续页面的加载速度。具体的技术原理和实现过程请看下文。

 >工作原理 

quicklink 通过以下措施加快后续页面的加载速度:

  • 检测 viewport 中的链接,使用 Intersection Observer:

    https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

  • 等待浏览器空闲,使用 requestIdleCallback:

    https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback

  • 检查用户的连接速度(使用 navigator.connection.effectiveType)或者是否启用了 data-saver(使用 navigator.connection.saveData);

  • 预取链接(使用或 XHR),可以控制请求优先级(如果支持,可以切换到 fetch())。

 >为什么要推出 quicklink? 

quicklink 旨在成为根据用户 viewport 中的链接预取内容的简易解决方案,而且要保持很小的体积(压缩后小于 1KB)。

 >安  装  

npm install --save quicklink

也可以从 unpkg.com/quicklink 下载 quicklink。

 >用  法 

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

<!-- Include quicklink from dist -->
<script src="dist/quicklink.umd.js"></script>
<!-- Initialize (you can do this whenever you want) -->
<script>
quicklink();
</script>

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

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

ES 模块导入:

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

上面的选项最适合多页面网站。单页应用程序也有几个可用的选项:

 

  • 在完成新路由导航后调用 quicklink();

  • 针对特定的 DOM 元素 / 组件调用 quicklink();

  • 使用自定义 URL 调用 quicklink({urls:[…]}) 进行预取。

    >API 

quicklink 可以接受带有以下参数的可选选项对象:

 

  • el:包含需要预取的链接的 DOM 元素;

  • urls:要预取的 URL 数组(不是在 viewport 中检测到的文档或 DOM 元素的链接);

  • timeout:requestIdleCallback 超时时间,浏览器执行预取的时间(以毫秒为单位),默认为 2 秒;

  • timeoutFn:用于指定超时的函数,默认为 requestIdleCallback,也可以替换为 networkIdleCallback(https://github.com/pastelsky/network-idle-callback)等自定义函数;

  • priority:布尔值,指定预取优先级,默认为 false。如果设置为 true,将尝试使用 fetch() API(而不是 rel=prefetch);

  • origins:允许预取的 URL 主机名字符串数组。默认为与域名相同的 origin,防止跨 origin 请求;

  • ignores:一个 RegExp 函数或数组,用于决定是否应该预取某个 URL。在 orign 匹配之后执行。

待完成事项:

  • 检测资源的文件扩展名,并使用 rel=preload 进行高优先级预取;

  • 使用 Priority Hints(https://github.com/WICG/priority-hints)进行重要性提示。

 >polyfill 

quicklink:

  • 可以回退到 requestIdleCallback;

  • 需要支持 IntersectionObserver,请参阅 CanIUse(https://caniuse.com/#feat=intersectionobserver)。我们建议使用 Polyfill.io 等服务来有条件地 polyfill 该功能:

<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>

 >一些示例 

 设置自定义的资源预取超时时间

默认为 2 秒(通过 requestIdleCallback),在这里我们将其设置为 4 秒:

quicklink({
  timeout: 4000
});

 设置包含预取 URL 的 DOM 元素

如果不设置,默认为 document。

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

 设置预取 URL 数组

如果你想要直接提供预取 URL 的列表,而不是去检测 viewport,可以使用 URL 数组。

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

 设置预取的请求优先级

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

quicklink({ priority: true });

 指定 origin 自定义列表

提供可预取的主机名列表。默认情况下只允许来自相同 origin 的 URL。

quicklink({
  origins: [
    // add mine
    'my-website.com',
    'api.my-website.com',
    // add third-parties
    'other-website.com',
    'example.com',
    // ...
  ]
});

 允许所有 origin

启用所有跨 origin 请求。

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

 自定义 Ignore 模式

这些过滤器在 origin 匹配之后运行,对于避免下载大文件或动态响应 DOM 属性来说非常有用。

// Same-origin restraint is enabled by default.
//
// This example will ignore all requests to:
//  - all "/api/*" pathnames
//  - all ".zip" extensions
//  - all <a> tags with "noprefetch" attribute
//
quicklink({
  ignores: [
    /\/api\/?/,
    uri => uri.includes('.zip'),
    (uri, elem) => elem.hasAttribute('noprefetch')
  ]
});

你可能希望忽略包含 URL 片段的 URL(例如 index.html #top)。如果你在页面中使用了锚点或为单页面应用程序设置了 URL 片段,希望避免触发此类 URL 的预取, 那么这项功能非常有用。

quicklink({
    ignores: [
        uri => uri.includes('#')
        // or RegExp: /#(.+)/
        // or element matching: (uri, elem) => !!elem.hash
    ]
});

 >浏览器支持 

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

  • 没有 polyfill:Chrome、Firefox、Edge、Opera、Android Browser, Samsung Internet。

  • 使用 Intersection Observer polyfill:Safari、IE11。

  • 上面的再加上 Set() 和 Array.from polyfill:IE9 和 IE10。Core.js(https://github.com/zloirock/core-js)提供了 Set() 和 Array.from() 填充,也可以考虑 es6-shim:

    https://github.com/paulmillr/es6-shim/blob/master/README.md

提供了某些功能的分层支持:

  • Network Information API(https://wicg.github.io/netinfo/),用于检查用户的连接类型(通过 navigator.connection.effectiveType),仅适用于 Chrome 61+ 和 Opera 57+。

  • 如果选择{priority: true}并且 Fetch API 不可用,则将使用 XHR。

 >直接使用 prefetcher 

quicklink 包含一个 prefetcher,可以单独导入到其他项目中使用。在将 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>

 >演 示 

这里是一个 WebPageTest 演示:

https://www.webpagetest.org/video/view.php?id=181212_4c294265117680f2636676721cc886613fe2eede&data=1

通过使用 quicklink,将页面加载时间减少了 4 秒。这里是进行预取前后的比较视频:https://youtu.be/rQ75YEbJicw。

出于演示的目的,我们在 Firebase 上部署了一个谷歌博客,然后我们又部署了另一个版本,在主页上添加了 quicklink,并测试从主页导航到文章的速度,结果预取版本的加载速度更快。

请注意:这并不是一个针对 viewport 内链接预取优缺点的详尽基准测试,我们只是演示了这个方法可以为我们带来的潜在改进。

英文原文:

https://github.com/GoogleChromeLabs/quicklink

© 著作权归作者所有

共有 人打赏支持
JamesView
粉丝 10
博文 105
码字总数 27771
作品 0
海淀
前端工程师
私信 提问
记录从quicklink源码中发散出来的知识点

最近Google Chrome lab的一个开源项目quicklink很火,号称可以极大提升页面的加载速度,社区中也有很多使用该项目来做页面加载优化的尝试,但quicklink项目本身的实现其实极为简洁,源码总共...

墨筝
2018/12/22
0
0
【性能优化】quicklink:实现原理与给前端的启发

近来,GoogleChromeLabs 推出了 quicklink,用以实现链接资源的预加载(prefetch)。本文在介绍其实现思路的基础上,会进一步探讨在预加载方面前端工程师还可以做什么。 1. quicklink 是什么...

AlienZHOU
2018/12/26
0
0
结合 Google quicklink,react 项目实现页面秒开

对于前端资讯比较敏感的同学,可能这两天已经听说了 GoogleChromeLabs/quicklink 这个项目:它由 Google 公司著名开发者 Addy Osmani 发起,实现了:在空闲时间预获取页面可视区域内的链接,...

LucasHC
2018/12/17
0
0
css过渡,css动画,页面布局分析,表单元素

一、css过渡 / 1.css样式在发生变化时,默认是直接变化,没有过渡的动画效果 / / 将某个样式设置为过渡时,这个样式在发生变化时,会执行过渡动画 / / transition-property: background-colo...

Mr_zebra
2018/09/07
0
0
图像加载库--AntiModerate

AntiModerate 是 Javascript 逐行扫描的图像加载库。它在加载图像时现在页面上显示一个微缩的模糊图像,同时在后台加载全图,它在低连接速率里将图像加载时间降到一秒之内。...

孔小菜
2015/11/09
555
0

没有更多内容

加载失败,请刷新页面

加载更多

深入 理解char * ,char ** ,char a[ ] ,char *a[] 的区别

C语言中由于指针的灵活性,导致指针能代替数组使用,或者混合使用,这些导致了许多指针和数组的迷惑,因此,刻意再次深入探究了指针和数组这玩意儿,其他类型的数组比较简单,容易混淆的是字...

天王盖地虎626
23分钟前
1
0
关于我这三年的架构历程(待完成)

从16年7月实习至今,快三年的开发经历中,经手了好几个项目。目前有幸作为一个项目的负责人,完成了一个项目的完全架构设计。因此想记录下这份架构设计中的点点面面。 总架构: 基于DNS的负载...

赵熠熠
24分钟前
0
0
springboot 使用 flyway 进行数据库版本管理

要在启动时自动运行Flyway数据库迁移,请将其添加 org.flywaydb:flyway-core到类路径中。 迁移是表单中的脚本V<VERSION>__<NAME>.sql(使用<VERSION>下划线分隔的版本,例如“1”或“2_1”)...

NotFound403
43分钟前
4
0
spring 5.1.5版本(二)

spring 5.1.5版本(一) spring 5.1.5版本(二) spring 5.1.5版本(三) 对象创建方式 方式一 applicationContext.xml <?xml version='1.0' encoding='UTF-8'?><beans xmlns="http://ww......

gwl_
45分钟前
0
0
CMake生成Mingw用的Make文件

CMake 在win下 默认会生成vc++的nmake用的make 当没安装时 就会报 -- Building for: NMake Makefiles -- The C compiler identification is unknown -- The CXX compiler identification is......

shzwork
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部