使用 InstantClick 加速网站

使用 InstantClick 加速网站

Tags
开发
FED
Description
InstantClick is a JavaScript library that dramatically speeds up your website, making navigation effectively instant in most cases.
Published
June 11, 2019

简介

instantclick.js 是一种ajax无刷新( PushState + Ajax)和预加载页面的技术,对于普通(传统)的Web应用,有着明显的加速作用。
instantclick.js所用的Pjax相对来说是一项很老的技术了。在当前React、Vue、Angular引领的现代化前端开发大环境下,单页应用变的很普及,instantclick.js就显得逊色不少。但是针对于之前的服务端渲染技术而言,对网站加速,实现类似的局部刷新还是很有用的。
本博客技术选型:Koa2 + MongoDB + Pug模板引擎,至于为什么选择基于模板引擎的服务端渲染,也经过较多的考量,后期将会有专门的文章讲解。
在博客搭建完成后使用instantclick.js,博客加载速度明显加快,整体的用户体验增强不少。下面就大概总结下instantclick的用法和可能会踩到的坑(大部分内容来自instantclick官网):

基本使用

下载instantclick.js

最新的发布版本是2014/12/25发布的V3.1.0

其他的下载方式

  • github上面的最新开发版本
  • 通过bower安装 : bower install instantclick

初始化instantclick

把 instantclick.js 和 初始化代码 放在你的页面的结束之前(</body>标签结束之前)
<script src="instantclick.min.js" data-no-instant></script> <script data-no-instant>InstantClick.init();</script> </body> </html>
现在instantclick 已经成功在你的网页上面生效。instantclick主要涉及到以下几个方面:
  • instantclick 工作原理
  • 预加载页面:将会向你展示不同的预加载页面的方法
  • 黑名单规则:因为有些链接你不想预加载
  • 事件和脚本的重新加载:将会帮助你使instantclick更好的配合你的网页中的JavaScript。
instantclick不总是“即插即用”(不是通过两行代码就可以在你的网页上运行),你可能需要自定义一些设置来适应你的网站,这也是为什么阅读上述文章是强制性的。

instantclick 工作原理

InstantClick与传统的web应用区别不大,但是很有必要去了解这些不同的地方!
instantclick使浏览器不再刷新整个页面(即无刷新页面效果)
首先:你需要理解的核心内容是:instantclick在技术上使你的网站成为单页应用程序;浏览器不再刷新整个页面,而是通过instantclick技术来更改页面内容,这意味着:
  • 你不能依赖DOMContentLoadedjQuery.ready()这两个函数来触发相关事件(这两个事件在刷新整个页面的时候才会触发,但是你可以使用InstantClick’s events来替代)
  • 依赖上面两个函数的第三方脚本(比如js代码)需要调整
  • 在加载页面的时候,浏览器不会在显示原本加载进度条了,instantclick有它自己的加载进度条。
其次:你需要明白instantclick只会改变<body>title,所以你的脚本只会被加载一次(带来的好处是速度的明显提升)。
注意:由于instantclick只会改变<body>title,所以页面的metalinkscript标签 等并不会再次加载,这里也就带来了不少问题:
  • 页面跳转页面的keywordsdescription 等不会改变,但不会影响到SEO,可以忽略不管。
  • 由于head中除了title外的数据都不会被重新加载,当新页面引入了新的style文件,JavaScript文件等是无效的,之前这个问题找了很久,注意避开这个坑。
  • 统计代码等失效(这个后面会讲到)。
下面还有一些内容你需要了解:
  • 通过instantclick加载的每个页面的<head>标签里面的样式和脚本应该是相同的(因为instantclick只会加载一次<head>标签里的内容)
  • 如果<head>标签里面的某些内容依赖于网页的内容(比如在页面加载时运行的脚本或css动画),它需要调整以便正常运行。
InstantClick是渐进式增强功能:如果访问者的浏览器不支持InstantClick,您的网站链接将照常工作,只是不会提升速度了。

预加载页面

InstantClick 关于预加载方式有多种选择。你可以根据你的服务器配置来选择合适的方式。
但是不管怎样,当每个页面改变时,不会重新加载脚本和样式表,这样会使你的页面加载速度提升一倍!(与Turbolinks、pjax等等技术是类似的)

默认: 在鼠标悬停预加载(mouseover)

当用户鼠标悬停在链接上开始预加载页面。如果用户网络链接不错的话,你的页面会很快的打开。
这个可以在instantclick初始化的时候设置

不会给服务器带来额外负担:在鼠标点击的瞬间预加载(mousedown)

当用户按下你的链接按钮的瞬间,页面开始预加载。这为你的服务器带来了接近零的开销,但仍然能够带来一个很“神奇”的速度提升!
使用方法:将'mousedown'作为参数传递给InstantClick.init
InstantClick.init('mousedown');

折中的方式:鼠标悬停延迟一定时间才会预加载

如果用户在您选择的延迟过后仍悬停在链接上,则该网页将开始预加载。
推荐的延迟时间为:100ms和50ms。超过100ms效果比mousedown效果更差。低于50ms,则会与mouseover效果相似。
要使InstantClick延迟一定时间后预加载,请将延迟(毫秒)作为参数传递给InstantClick.init。
InstantClick.init(50);

手机端效果

上面的任何预加载方式,在手机端的时候,当用户手指接触链接时候都会开始预加载。
如果您的网站针对移动设备(在安卓和iOS界面上使用了FastClick技术)进行了优化,则当访问者从链接中释放手指时,会发生“点击”,导致预加载大约100 ms的延迟。
如果您的网站没有针对手机进行优化,延迟时间则取决于操作系统。 Android为300 ms,iOS为450 ms。
在同一站点上的3G请求的延迟时间通常需要大约200ms。

如何选择?

如果您的网站可以处理额外的负载,选择 在鼠标悬停时预加载方式。
如果你的网站不能,选择在鼠标点击的瞬间预加载方式。您的网站的速度仍然会超过99%的网站。
如果你想确定你的服务器是否可以,先选择在鼠标点击的瞬间预加载方式,你的服务器几乎不会有额外的压力。然后使用鼠标悬停延迟100毫秒预加载。然后50毫秒延迟(或减少更小的减少,如果你有耐心)。然后直接用在鼠标悬停时预加载,分别看你的服务器是否能够承受额外的负担。
如果服务器端分析很重要,你只能使用在鼠标点击的瞬间预加载,使用任何其他方式都会带来误差。

黑名单规则

有一些链接是不需要通过instantclick来预加载。黑名单规则可以实现这个效果。

哪些需要进入黑名单

哪些需要进入黑名单,而不能进入白名单的:
  • 指向操作的链接,例如注销和切换语言。
  • 链接指向需要一段时间加载的非HTML内容
  • 链接指向的页面与当前页面<head>标签内的css样式和脚本不同
  • 链接触发JavaScript的操作
部分链接已在内部列入黑名单,且无法列入白名单:
  • 链接有target或者download属性
  • 链接与当前的域名或者协议不同
  • 链接指向当前页面的锚点链接(#anchor)

把一个链接列入黑名单

把一个链接加入黑名单,只需要在链接中加入data-no-instant属性
<a href="/blog/" data-no-instant>Blog</a>

把一组链接列入黑名单

有时候要把一组链接一起列入黑名单,这时候比给所有链接分别添加data-no-intant要方便的多。
把父元素内部的所有链接列入黑名单,只需要向该父元素添加data-no-instant属性。

把一个链接或者一组链接列入白名单

如果您已将某个父元素列入黑名单,并且希望将其中的某个链接(或者子元素内部的所有链接)列入白名单,只需要向该链接或子元素添加data-instant属性。
InstantClick在后台中从当前链接的位置到</html>的位置,遍历所有的父元素,如果找到data-no-instant属性,它就会认为该链接已经被列入黑名单,并停止循环遍历父元素。如果它找到data-instant属性,它会认为该链接已经被列入白名单。
如果您希望默认将所有链接列入黑名单,然后逐个将链接列入白名单或仅想把某个容器的链接列入白名单,请在<body>添加一个data-no-instant属性,然后向该链接或者容器中添加data-instant属性。

白名单模式

下面的方法已经弃用,可能会在4.0版本中删除。只有当你配置InstantClick.init(true),白名单模式才会生效。
正确的方式™:如果要实现与白名单模式相同的效果,只需添加data-no-instant到你的<body>标签中,参见上一条目“把一个链接或者一组链接列入白名单”。
通过向InstantClick.init传递true参数来启用白名单模式。
InstantClick.init(true); /* or */ InstantClick.init(50, true); /* or */ InstantClick.init('mousedown', true);

事件和脚本的重新加载

InstantClick技术上使你的网站成为单页应用程序,因此当页面切换的时候,不会触发DOMContentLoaded函数。因此,一些脚本可能需要调整才能与InstantClick正常工作。
InstantClick会触发4个事件以便于挂钩到页面的整个生命周期:
  • change:当前的页面一旦改变会触发该事件,即使浏览器不支持instantclick,页面初始加载的时候也会触发该事件,这个事件可以用来替换DOMContentLoaded.
  • fetch:页面开始预加载的时候
  • receive:页面已经预加载完成,你可以使用该事件修改页面的内容.
  • wait:用户已经点击了链接,但是页面还没有开始预加载。仅在页面不是立即显示(可能由于网络原因)的时候触发。
监听一个事件,比如change,你可以使用InstantClick.on:
InstantClick.on('change', yourCallback);
您需要在InstantClick.init之前调用InstantClick.on,因为change事件在网页初始加载时就会被触发,包括浏览器不支持pushState的时候。

如果在<body>标签内部有一个脚本,当instantclick切换到另一个页面的时候,你并不希望重新加载它 ,你可以添加一个data-no-instant属性。
<script data-no-instant>alert("I’m only run once.");</script>
如果有一些脚本与instantclick发生冲突,建议向所有脚本添加一个data-no-instant属性,然后逐个删除每个属性,直到找到罪魁祸首。您可以通过查看Turbolinks兼容性站点上的示例(在CoffeeScript中)了解如何解决兼容性问题。

例如,以下是如何使Google Analytics(网站统计与分析)(2013年末的代码)正常工作:
<script src="instantclick.min.js" data-no-instant></script> <script data-no-instant> /* Google Analytics code here, without ga('send', 'pageview') */ InstantClick.on('change', function() { ga('send', 'pageview', location.pathname + location.search); }); InstantClick.init(); </script>

receive事件里改变页面内容

有时,即时改变页面内容比为instantclick重构你的后端代码要简单。你可以使用receive事件。
这个事件有三个参数:url, ,body 和title
url 接收的页面的地址,它包括哈希值。它是只读的。
body是body对象,title是标题文本。如果你想在页面显示之前改变页面内容,你可以修改这两个参数并返回一个对象(或者只修改其中的一个参数)。
下面是一个例子:
InstantClick.on('receive', function(url, body, title) { var dont_display = body.querySelector('#dont_display_me_when_loaded_with_instantclick') if (dont_display) { dont_display.setAttribute('hidden', ''); } title += ' (loaded with InstantClick)'; return { body: body, title: title }; });
要记住 body 对象是body 而不是document.body!
当您有多个回调函数监听receive函数时,每个后续回调将获得最后更改的内容。
如果你不想修改页面内容,则不用返回任何内容或返回false

进阶阶段

跟踪页面内容的变化

当前跟踪页面内容的变化的方式目前有点笨拙。它可能稍后在InstantClick 4.0中更改。
要检查样式表或脚本(外部或内联)何时更新,请添加一个data-instant-track属性:
<link rel="stylesheet" href="style.css" data-instant-track> <script src="script.js" data-instant-track></script> <style data-instant-track>body { background: aliceblue; }</style> <script data-instant-track>window.timingStart = performance.now();</script>
InstantClick将检查hrefsrc属性(如果存在)中的更改。要指示文件已更新,请修改其属性:
<link rel="stylesheet" href="style.css?20140308" data-instant-track> <script src="script.js?20140308" data-instant-track></script>
如果它是内联脚本或样式,InstantClick将检查元素内容中的更改。
<style data-instant-track>body { background: midnightblue; font: 13px Helvetica; }</style> <script data-instant-track>var timingStart = performance && performance.now();</script>
当检测到任何更改时,InstantClick将重新加载页面,从而使浏览器重新评估所有脚本和样式。

自定义加载条

进度条是一个假的进度条,只是在那里给你的用户的感觉页面的加载进度。
在未来,应该可以使进度条显示真正的进度(通过查看服务器的Content-Length头)。
即使页面已经立即加载,也会显示进度条,在将来这将更改。你可以在github讨论。
当访问者缩放页面或旋转其设备时,该栏的大小和位置会自动调整,因此即使您的网站未针对移动设备进行优化,也会正常工作。
默认情况下,进度条的颜色为#29d, 你可以改变CSS:
#instantclick-bar { background: white; }
你也可以让进度条消失:
#instantclick { display: none; }
使进度条消失的方式不是最佳的。在稍后的InstantClick版本中,可能可以通过向InstantClick.init传递参数来实现这个效果。