resouce hintsとpreloadを使ってリソースの取得を最適化する

Resource HintsPreloadを使うことでリソースの取得を最適化できるようなので試してみた。

もともとはHTTP2にしてServer Pushを使うことで、予めリソースをサーバー側から送ることができるが、
ブラウザのキャッシュのメリットを活用できないんじゃないかということが気になっていた。
また、単純にHTTP2対応してもウェブページにはcrossoriginなリソースを多く利用しているので、
そのパフォーマンスの問題は解決しないのではないかという疑問があった。

それらを解決する手段としてResource Hintsなどを使ったPrebrowsingの技術が活用できそう。

preloadに関してはPreload: What Is It Good For?がまとまっているので参考にした。

Resource Hints について

Resource Hints はlink要素に dns-prefetchpreconnectprefetchprerenderのいずれかを指定することで、取得するリソースに対してバックグラウンドで事前に処理をすることで、遷移後のページのパフォーマンス向上に寄与できる。
次に遷移するページで必要なリーソースをバックグランドで取得し、遷移後にページが表示されるまでの時間を短縮することができる。
Browserプロセスの裏側でRenderプロセスがPrebrowsing処理する感じ。

例えば

  • ログイン前にPrebrowsingして、ログイン後のページの表示パフォーマンスを向上させる
  • 商品購入前にPrebrowsingして、商品詳細ページの表示パフォーマンスを向上させる
  • ユーザー登録フォームの前にPrebrowsingして、登録フォームの表示パフォーマンスを向上させる

など、多くのウェブアプリケーションでありそうなもので活用できる。

試してみる

以下のようなファイルに対してHTTP2をつかってResource Hintsを試してみる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!doctype html>
<html class="no-js" lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Sample</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="apple-touch-icon" href="apple-touch-icon.png">

<!-- normalize -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css" integrity="sha384-+K7c3ujxU/SqpJg+sVdgOemJ3tcpzSGHWv3+1TgPb20j3DmE2srNJo5kVStOVq4k" crossorigin="anonymous">

<!-- bootstrap -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">

<!-- font awasome -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" href="//fortawesome.github.io/Font-Awesome/assets/font-awesome/fonts/fontawesome-webfont.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<!--[if lt IE 8]>
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->

<!-- Add your site or application content here -->
<p>Hello world! This is HTML5 Boilerplate.</p>

<!-- bootstrap -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

<!-- modernizr -->
<script src="//ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script>

<!-- jQuery -->
<script src="//code.jquery.com/jquery-1.12.1.js" integrity="sha256-VuhDpmsr9xiKwvTIHfYWCIQ84US9WqZsLfR4P7qF6O8=" crossorigin="anonymous"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>

<!-- Google Analytics: change UA-XXXXX-Y to be your site's ID. -->
<script src="//www.google-analytics.com/analytics.js" async defer></script>
</body>
</html>

このファイルへのアクセスをChrome Dev ToolのNetwork panelで見てみる

このような感じ。

dns-prefetch

DNSによる名前解決をできるだけ早くおこなうことで、ページ読込み時にかかる名前解決によるコストを下げる。
多くのブラウザですでにサポートされている

1
<link rel="dns-prefetch" href="//example.com">

amazon.comでは以下のように活用されている模様。
x-dns-prefetch-control でDNS Prefetch機能をユーザーの意志とは関係なく実装できる。

1
2
3
4
5
6
7
8
9
<!-- from amazon.com -->
<meta http-equiv="x-dns-prefetch-control" content="on">
<link rel="dns-prefetch" href="//g-ec2.images-amazon.com">
<link rel="dns-prefetch" href="//ecx.images-amazon.com">
<link rel="dns-prefetch" href="//z-ecx.images-amazon.com">
<link rel="dns-prefetch" href="//z-ak.images-amazon.com">
<link rel="dns-prefetch" href="//completion.amazon.com">
<link rel="dns-prefetch" href="//fls-fe.amazon.co.jp">
<link rel="dns-prefetch" href="//d1y6jrbzotnyjg.cloudfront.net">

実際に次のようなページを作成して試してみた。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-dns-prefetch-control" content="on">
<title>DNS-Prefetch</title>
<link rel="dns-prefetch" href="//:cdnjs.cloudflare.com">
<link rel="dns-prefetch" href="//:maxcdn.bootstrapcdn.com">
<link rel="dns-prefetch" href="//:ajax.aspnetcdn.com">
<link rel="dns-prefetch" href="//:code.jquery.com">
<link rel="dns-prefetch" href="//:www.google-analytics.com/">
</head>
<body>
<a href="main.html">main page</a>
</body>
</html>

CDNを使っているので名前解決にそこまで時間がかかっていないが、それでも名前解決の時間が短縮されている。

preconnect

DNSルックアップ、TCPハンドシェイク、TLSネゴシエーションまでを事前に処理することができる。
schemeはhttp, httpsのみが許可されていて、crossorigin属性が定義されている。
ちなみに2016/03 現在ではChromeとFirefoxではサポートされている様子。

1
2
<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>

また、Resource Hintはlinkタグを挿入したらいいということでJavaScriptを使えば簡単に動的に追加もできる。

1
2
3
4
5
6
function preconnect(url) {
var hint = document.createElement('link');
hint.rel = 'preconnect';
hint.href = url;
document.head.appendChild(hint);
}

実際に遷移前のページとして以下のようなものを使う

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Preconnect</title>
<link rel="preconnect" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css" crossorigin="anonymous">
<link rel="preconnect" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" crossorigin="anonymous">
<link rel="preconnect" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" crossorigin="anonymous">
<link rel="preconnect" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" crossorigin="anonymous">
<link rel="preconnect" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" crossorigin="anonymous">
<link rel="preconnect" href="//ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js" crossorigin="anonymous">
<link rel="preconnect" href="//code.jquery.com/jquery-1.12.1.js" crossorigin="anonymous">
<link rel="preconnect" href="//www.google-analytics.com/analytics.js" crossorigin="anonymous">
</head>
<body>
<a href="main.html">main page</a>
</body>
</html>

Chromeで chrome://net-internals/#dns を見てみると

Hostname Family Addresses Expires
ajax.aspnetcdn.com IPV4 68.232.45.201 2016-03-09 15:05:55.444 [Expired]
cdnjs.cloudflare.com IPV4 198.41.215.66
198.41.215.67
198.41.214.67
198.41.214.68
198.41.215.68
2016-03-09 15:05:55.443 [Expired]
code.jquery.com IPV4 94.46.159.11 2016-03-09 15:05:55.444 [Expired]
maxcdn.bootstrapcdn.com IPV4 94.31.29.154 2016-03-09 15:05:55.442 [Expired]
www.google-analytics.com IPV4 216.58.197.206 2016-03-09 15:05:55.474 [Expired]

Chromeで chrome://net-internals/#events でも確認

ID Source Type Description
534655 CONNECT_JOB pm/ssl/cdnjs.cloudflare.com:443
534656 CONNECT_JOB pm/ssl/cdnjs.cloudflare.com:443
534657 HOST_RESOLVER_IMPL_JOB cdnjs.cloudflare.com
534658 HTTP_STREAM_JOB https://maxcdn.bootstrapcdn.com/
534659 CONNECT_JOB pm/ssl/maxcdn.bootstrapcdn.com:443
534660 CONNECT_JOB pm/ssl/maxcdn.bootstrapcdn.com:443
534661 HOST_RESOLVER_IMPL_JOB maxcdn.bootstrapcdn.com
534662 HTTP_STREAM_JOB https://maxcdn.bootstrapcdn.com/
534663 HTTP_STREAM_JOB https://maxcdn.bootstrapcdn.com/
534664 HTTP_STREAM_JOB https://maxcdn.bootstrapcdn.com/
534665 HTTP_STREAM_JOB https://ajax.aspnetcdn.com/
534666 CONNECT_JOB pm/ssl/ajax.aspnetcdn.com:443
534667 CONNECT_JOB pm/ssl/ajax.aspnetcdn.com:443
534668 HOST_RESOLVER_IMPL_JOB ajax.aspnetcdn.com
534669 HTTP_STREAM_JOB https://code.jquery.com/
534670 CONNECT_JOB pm/ssl/code.jquery.com:443
534671 CONNECT_JOB pm/ssl/code.jquery.com:443
534672 HOST_RESOLVER_IMPL_JOB code.jquery.com
534673 HTTP_STREAM_JOB https://www.google-analytics.com/
534674 CONNECT_JOB pm/ssl/www.google-analytics.com:443
534675 CONNECT_JOB pm/ssl/www.google-analytics.com:443
534676 HOST_RESOLVER_IMPL_JOB www.google-analytics.com
534677 SOCKET pm/ssl/ajax.aspnetcdn.com:443
534678 SOCKET pm/ssl/cdnjs.cloudflare.com:443
534679 SOCKET pm/ssl/maxcdn.bootstrapcdn.com:443
534680 SOCKET pm/ssl/code.jquery.com:443
534681 SOCKET pm/ssl/www.google-analytics.com:443

確かに事前にリクエストしていることがわかる。
アクセスしてみる。Google dev toolのNetwork pannelから

すでにconnectしているまでは完了しており、ダウンロードするだけとなり早い。

prefetch

ページを予めダウンロードまでおこない、キャッシュに格納する。
リソースのサイズが大きい場合やネットワークが遅い場合などはブラウザはprefetchを行わない。
またas属性でリソースを適切なコンテキストを指定でき、これによりブラウザは最適なfetchプロセスでresourceを取得する。

prefetchは最近のブラウザではだいたいサポートされてる。

1
2
<link rel="prefetch" href="//example.com/next-page.html" as="html" crossorigin="use-credentials">
<link rel="prefetch" href="/library.js" as="script">

こちらもChromeで chrome://net-internals/#events を見てみると

ID Source Type Description
538454 URL_REQUEST https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css
538456 URL_REQUEST https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css
538458 URL_REQUEST https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css
538460 URL_REQUEST https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css
538462 URL_REQUEST https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
538464 URL_REQUEST https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
538466 URL_REQUEST https://code.jquery.com/jquery-1.12.1.js
538468 URL_REQUEST https://www.google-analytics.com/analytics.js
538470 DISK_CACHE_ENTRY https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css
538471 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css
538472 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css
538473 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css
538474 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
538475 DISK_CACHE_ENTRY https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
538476 DISK_CACHE_ENTRY https://code.jquery.com/jquery-1.12.1.js
538477 DISK_CACHE_ENTRY https://www.google-analytics.com/analytics.js

リクエストからcacheまで行われている。

Chrome dev toolのNetwork pannelでもリクエストしていることが見てわかる。

実際にcssを読込んでいるページに遷移してみると、cacheしているので早い。

prerender

事前にバックグランドで指定リンク先のリソースをダウンロードし、DOM構築、JavaScriptの実行、CSS適用、レイアウトまで行う。
Render Processですでにページを構築している感じなるっぽい。(見えないタブでページを描画してしまってる感じ)
よって、遷移後はタブが切り替わるのように、ページがすぐに表示されるようになる。

1
<link rel="prerender" href="//example.com/next-page.html">

サポートは2016/03 現在ChromeとEdge、Operaがサポートしている。

こちらも同じ感じのhtmlを準備して試してみる。

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Prerender</title>
<link rel="prerender" href="main.html">
</head>
<body>
<a href="main.html">main page</a>
</body>
</html>

こちらは遷移先のページ(prerender.htmlとした)を指定して、試してみる。
Chromeで chrome://net-internals/#events を見てみると

ID Source Type Description
561062 URL_REQUEST https://192.168.99.100:8443/main.html
561064 DISK_CACHE_ENTRY https://192.168.99.100:8443/main.html
561065 HTTP_STREAM_JOB https://192.168.99.100:8443/
561066 URL_REQUEST https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css
561068 URL_REQUEST https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css
561070 URL_REQUEST https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css
561072 DISK_CACHE_ENTRY https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css
561073 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css
561074 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css
561075 URL_REQUEST https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css
561077 URL_REQUEST https://fortawesome.github.io/Font-Awesome/assets/font-awesome/fonts/fontawesome-webfont.woff2
561079 URL_REQUEST https://192.168.99.100:8443/css/main.css
561081 URL_REQUEST https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
561083 URL_REQUEST https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
561085 URL_REQUEST https://code.jquery.com/jquery-1.12.1.js
561087 URL_REQUEST https://192.168.99.100:8443/js/plugins.js
561089 URL_REQUEST https://192.168.99.100:8443/js/main.js
561091 URL_REQUEST https://www.google-analytics.com/analytics.js
561093 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css
561094 DISK_CACHE_ENTRY https://fortawesome.github.io/Font-Awesome/assets/font-awesome/fonts/fontawesome-webfont.woff2
561095 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
561096 DISK_CACHE_ENTRY https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
561097 DISK_CACHE_ENTRY https://code.jquery.com/jquery-1.12.1.js
561098 DISK_CACHE_ENTRY https://www.google-analytics.com/analytics.js
561099 DISK_CACHE_ENTRY https://192.168.99.100:8443/css/main.css
561100 DISK_CACHE_ENTRY https://192.168.99.100:8443/js/plugins.js
561101 DISK_CACHE_ENTRY https://192.168.99.100:8443/js/main.js
561102 HTTP_STREAM_JOB https://192.168.99.100:8443/
561103 HTTP_STREAM_JOB https://192.168.99.100:8443/
561104 HTTP_STREAM_JOB https://192.168.99.100:8443/
561105 DISK_CACHE_ENTRY https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
561106 URL_REQUEST https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
561108 DISK_CACHE_ENTRY https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
561109 DISK_CACHE_ENTRY https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js
561110 URL_REQUEST https://code.jquery.com/jquery-1.12.1.js
561112 DISK_CACHE_ENTRY https://code.jquery.com/jquery-1.12.1.js
561113 DISK_CACHE_ENTRY https://code.jquery.com/jquery-1.12.1.js
561114 URL_REQUEST https://www.google-analytics.com/analytics.js
561116 DISK_CACHE_ENTRY https://www.google-analytics.com/analytics.js

リクエストされ、cacheもされている。しかし、こちらはChrome dev toolのNetwork pannelでは確認できない。
このまま該当ページに遷移する。

予めページの準備が整ってるだけあり、体感的にも早い。

preload

こちらはResource Hintsではなく、別の機能としてドキュメントも分けられている。
利用するにはResource Hintsと同様にlinkタグを用いる。

Chrome version 50 からサポートされる様子
2016/03/19 現在はcanaryでは利用できる。

1
2
3
4
<link rel="preload" href="/assets/font.woff" as="font">
<link rel="preload" href="/style/other.css" as="style">
<link rel="preload" href="//example.com/resource">
<link rel="preload" href="https://fonts.example.com/font.woff" as="font" crossorigin>

または、HTTP response HeaderにLinkを追加することでも実現できる。

1
2
3
4
Link: https://example.com/font.woff; rel=preload; as=font
Link: https://example.com/app/script.js; rel=preload; as=script
Link: https://example.com/logo-hires.jpg; rel=preload; as=image
Link: https://fonts.example.com/font.woff; rel=preload; as=font; crossorigin

as属性にはfont、script、style、image、documentなどが利用できる。
リソースの種類の詳細はwidl-HTMLLinkElement-asから確認出来る

peloadの特徴

  • ページの読込をブロックしない
  • Resource Hintsが遷移前に次のページのResourceを先行して処理するのと異なり、
    現在のページにおいてResourceを先読みする。
  • 取得するリソースの優先度を設定できる。
  • Resourceをfetchする際にContent-Security-Policy(CSP)を確認できる
  • Resourceのタイプに応じたAcceptヘッダーを送ることができる
  • 将来的なResourceは再利用のために、ブラウザはResourceタイプを決定することができる

preloadのタグは任意のタイミングで動的に追加された場合、リソースの読み込みが開始される。
しかし、その時点では現在のページに対して、取得したリソースを実行をしたり、ページに適用をすることはない。

これらを踏まえて、いくつかのパターンでためしてみる。

動的にlinkタグを追加

JavaScriptで動的にlinkタグを追加して、任意のタイミングでpreloadする。
onloadイベントにてscriptタグを動的に生成することで、ページに適用できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
function addScripts() {
var script = document.createElement('script');
script.src = 'execute.js';
document.body.appendChild(script);
}

var link = document.createElement('link');
link.href = 'execute.js';
link.rel = 'preload';
link.as = 'script';
link.addEventListener('load', addScripts, false);
link.addEventListener('error', function(error) { console.log(error) }, false);
document.head.appendChild(link);
</script>

ウェブフォントの先読み

WebフォントをPreloadする。
webフォントの問題点として、パフォーマンスがあった。
実際にフォントの読込みが遅延することで、ページ全体のパーフォーマンスが低下します。
Preloadを利用することで、ブロッキングされないためパフォーマンスが向上する。

1
<link rel="preload" href="//fonts.googleapis.com/css?family=Montserrat" as="font" crossorigin>

バックグランウンドで先読みしてloadのタイミングで適用

任意のタイミングでPreloadして、Resource取得後にlinkタグのrel属性値をstylesheetに変えることで
直接cssを適用できる。

1
2
3
4
5
6
7
var link = document.createElement("link");
link.rel = "preload";
link.as = "style";
link.href = "css/style.css";
link.addEventListener('load', function() { this.rel = 'stylesheet' }, false);
link.addEventListener('error', function(error) { console.log(error) }, false);
document.head.appendChild(link);

メディアクエリ

media属性を用いることでレスポンシブにpreloadもできるようになる様子。
(現在はまだサポートされていない)
デバイスに応じて必要なリソースを取得することでsumartphoneなどでのページ表示のパフォーマンスの改善になりそう。

1
<link rel="preload" as="image" href="image-max-width.png" media="(max-width: 640px)">

HTTP2 Server Push との違い

peloadの場合はサードパーティーのresourceも先読みできる。
いっぽう、Server Pushではさすがにサードパーティーのresourceを先読みすることは難しい。

また、preloadの場合はブラウザのキャッシュを有効に活用できるほか、コンテントネゴシエーションも利用できる。
これに対してServer Pushは現在のところこれは利用できないため、すでにキャッシュできているResourceも一方的に送ってくる結果になってしまう。
h2oではcasper(cache-aware server-push)ディレクティブを追加してこのあたりを改善できるようにしよう策定している様子。

所感

HTTP2化のほかに、ブラウザキャッシュやサードパーティーのリソースなどを活用できるPrebrowsingも併用することで、
webアプリケーションのパフォーマンスの改善が期待できる。
とくにスマートフォンなどのマルチなデバイスをサポートしているサービスなどは活用した方が良い。

今回は前回利用したkazu69/h2o_mruby_playgroundの環境でためした。

参考にしたページ

https://www.chromestatus.com/feature/5757468554559488
https://www.chromium.org/developers/design-documents/prerender
https://developer.mozilla.org/ja/docs/Link_prefetching_FAQ
https://css-tricks.com/prefetching-preloading-prebrowsing/
https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/
https://github.com/w3c/preload/
https://github.com/igrigorik/resource-hints

Comments