8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ateam Finergy Inc.Advent Calendar 2019

Day 3

一部のWebサイト高速表示に一役買っている「InstantClick」について

Last updated at Posted at 2019-12-02

前書き

こちらはAteamFinergyのアドベントカレンダー3日目の記事になります。
内容としてはInstantClickの説明が大半を締めており
目的としては、InstantClickの認知を増やす事です

InstantClickとは

Webサイトを劇的に高速化するJavaScriptライブラリ」
-- from instantclick.io

JavaScriptのライブラリにInstantClickというものがあり、Webサイトに対して適用すると高速になる...というものがあり
そのInstantClickを実際に使用している例を上げると「dev.to」や「FC2爆速テンプレート」などで使用されています

特にdev.toについては阿部寛のホームページと比較している記事が多く見られ、ご存知のかたは多いのではないでしょうか

InstantClickではpjax(pushState + ajax)を使用して高速化を図っており
リンク先のHTMLをpreloadしておき、リンク先へ遷移するタイミングに「head, body, title」を入れ替え、ユーザーに対してとても素早いページ遷移の体験を提供している様です。

pjaxは、ajaxを介してサーバーからHTMLを取得し、ページ上のコンテナ要素のコンテンツを読み込まれたHTMLに置き換える
-- from jquery-pjax

ブラウザ上のページを変更することはないがInstantClickによってHTML要素が変更され、結果SPAに近しい挙動となります

仕組みについて

リンク先のHTMLをpreloadすると言っても、Webサイトには無数のリンクがあるため、「どのタイミング」で「どのくらい」取得する事が大事になるはずです

InstantClickのデフォルトの設定では、遷移先のリンクに対して「マウスを重ねた瞬間」に「リンク先の要素」を取得するようです

実際にユーザーがリンクにマウスオーバーしてからクリックするまでの間に200~300ms経過するため、その間にリンク先をpreloadしておく事でスムーズな遷移を提供しています

実際にこちらで、「MouseOverイベントが走ってからクリックするまでの秒数」と「MouseDownイベントが走ってからクリックするまでの秒数」を確認する事ができるので一度見てみると良さそうです

また、モバイルについてはmouseoverではなく、touchstartイベントが対象となっているようです

実際にこちらを見ていただくと検証画面のInitiatorの箇所がInstantClickによって遷移先のHTMLを取得している事が確認できます
test.gif
FC2爆速テンプレートdemoページより

導入方法

導入の仕方についてはとても簡単で
「InstantClickをダウンロード」「ファイルを任意の箇所に配置」
「読み込みのscriptタグと初期化のscriptタグを記述」の3ステップで出来ます。

  1. こちらからProduction Versionをダウンロード
  2. InstantClickの読み込みをページの下部で実施
  <script src="instantclick.min.js" data-no-instant></script>
  <script data-no-instant>InstantClick.init();</script>
</body>

注意点

InstantClickを使用する際にはいくつか注意する事があります

JSで取得する事ができるイベントについて

InstantClickはpjaxの技術でHTMLを入れて表示を切り替えるので
DomContentLoaded jQueryのready() などのイベントが発火しなくなります。

そのため、InstantClickではいくつかの既存のライフサイクルをフックする事で解決します。

解決法: 既存ライフサイクルのフック

InstantClickでは下記の4つが提供されており、それぞれ元のイベントの代替になります。

  • change
    • DomContentLoadedの置き換えとなり、InstantClickが読み込まれていない最初の遷移時にも発火
  • fetch
    • マウスオーバーした時に、遷移先のHTMLをpreloadするタイミングで発火
  • recieve
    • preloadが完了したタイミングで発火
  • await
    • ユーザーがクリックしたがpreloadが完了していない待ち時間の間に発火

導入した際には
上記の様なイベントに既存のイベントが置き換わるため注意が必要です

サーバーへのリクエスト数

デフォルトの設定のままだと、マウスオーバーするだけでサーバーへリクエストを送る事になり、場合によってはサーバーへの負荷が高まることやブラウザ側では使用しないムダなHTMLを取得する事になります

そのため、InstantClickでは2つの解決策を用意しています。

  1. マウスダウンイベントへの変更
  2. マウスオーバー時のリクエスト遅延

解決法①: マウスオーバーからマウスダウンへの変更

InstantClickを初期化するタイミングでmouseoverイベントからmousedownイベントに変更する事ができます。

Webサイトによっては、マウスオーバー程効果を得る事が出来ない可能性はありますが
それでもマウスダウンからクリックするまでに80~120ms程度かかるのでその間に普段のページ遷移より体感としては早く行えます。
計測はこちら

初期化の記述にmousedownを引数として渡してあげるだけで変更できるようです

 <script data-no-instant>InstantClick.init('mousedown');</script>

実際に下記のコードを確認すると
初期化のタイミングでこの引数を渡すとdocumentに対してmouseovermousedownかのどちらのイベントをリッスンするか変更する事が確認できます
https://github.com/dieulot/instantclick/blob/master/src/instantclick.js#L804
https://github.com/dieulot/instantclick/blob/master/src/instantclick.js#L830

解決法②: マウスオーバー時のpreloadリクエストの遅延

デフォルトとマウスダウンへ変更した時とのちょうど間にある選択肢として
「マウスオーバー時にリクエストは送るけれど、カーソルが触れただけの時とかは無しにしたい」というケースでは
マウスオーバー時のリクエストを遅延させる事で解決できます

こちらを適用するには、マウスダウンへ変更した時と同様に、初期化のタイミングで何ms遅延させたいかを渡してあげるだけで大丈夫です
下記の例は75ms遅延させる時

 <script data-no-instant>InstantClick.init(75);</script>

実際のコードを確認すると
初期化で渡された引数が保存され、setTimeoutによって設定した時間分遅れてpreloadを実行するようです。
https://github.com/dieulot/instantclick/blob/master/src/instantclick.js#L454

ただ何も渡さない場合は65msにpreloadするようです。
https://github.com/dieulot/instantclick/blob/master/src/instantclick.js#L30

リンク毎のpreload制御

初期設定だと一部を除いてほとんどのリンクがpreloadの対象となります。

具体的には下記の様なリンクがpreloadの対象外となります

  • targetまたはdownload属性を所持している
  • 現在のWebサイトとは別のdomainまたはprotocol
  • 同じページへのanchor
<a href='https://qiita.com/' target='_blank'>not preload</a>
<a href='https://qiita.com/' download>not preload</a>
<a href='https://github.com/'>not preload</a>
<a href='http://qiita.com/'>not preload</a>
<a href='#InstantClickとは'>not preload</a>

ただ、使用する際に「ほとんどのリンクは適用したいけれど、このリンクはpreloadしたくない」などのケースが出てくる時があるでしょう
その時は「このリンク適用しない」と設定が可能な、ブラックリスト機能があります

解決法: ブラックリスト・ホワイトリスト機能

設定方法は簡単で、preloadして欲しくないリンクに対してdata-no-instant属性を付与するだけです。

<a href='https://qiita.com/' data-no-instant>not preload</a>

また、該当箇所が複数あった場合については親の要素にdata-no-instant属性を付与する事ですべての子要素に対してpreloadが走らなくなります。

<div data-no-instant>
  <a href='https://qiita.com/'>not preload</a>
  <a href='https://qiita.com/'>not preload</a>
  <a href='https://qiita.com/'>not preload</a>
</div>

複雑化した際の方法としては

  1. 親要素にdata-no-instantを記述して子要素をまとめてブラックリスト追加
  2. その子要素の任意のものだけdata-instant属性を追加する
    とする事でホワイトリストに追加し簡易的な対応ができます
<div data-no-instant>
  <a href='https://qiita.com/'>not preload</a>
  <a href='https://qiita.com/' data-instant>preload</a>
</div>

まとめ

  • InstantClickはpjaxで遷移先の値をpreloadし、入れ替える
  • 遷移先を取得するのはmouseoverイベントのタイミングなのでユーザーに素晴らしい体験を提供できる
  • サーバーへの負荷が高まる可能性がある
  • javascriptの元々のイベントを取得できなくなる

いかがだったでしょうか、InstantClick自体が少し古い技術かと思いますが「dev.toめっちゃはやいやんけ!」という仕組みの片鱗を知って、興味を持っていただけたら幸いです

引用元

http://instantclick.io/
https://developer.mozilla.org/ja/
https://dev.to/
https://fc2information.blog.fc2.com/
https://github.com/defunkt/jquery-pjax

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?