いわゆるファイルのプリフェッチとは、ページが正常にロードされた後、後でアクセスされる可能性のあるページのリソースをサイレントにプリロードすることです。実際、フロントエンド リソースのプリロードについては何も新しいことはありませんが、それを理解するプロセスは非常に興味深く、刺激的です。
1. プリロードする必要があるさまざまな CSS と JS のインデックスを作成するコードは次のようになります。
<html> <head> <link rel="stylesheet" href="//su.yzcdn.cn/v2/build_css/stylesheets/wap/showcase_d0fbaaef124a8691398704216ccd469a.css"> ...其他需要预加载的css</head><body> <script src="//su.yzcdn.cn/v2/build/wap/common_08b03c7826.js" onerror="_cdnFallback(this)"></script> ...其他需要预加载的js</body> </html>
2. 各ページを開いたときに上記のページが読み込まれるように、各ページに iframe を追加します (通常は基本テンプレートを通じて追加されます)。上記のページの URL が https://xxx.com/common/prefetching.html であると仮定すると、各ページの下部に次のコード行があります:
<iframe src="https://youzan.com/common/prefetching.html" sytle="display:none;"></iframe>
特定のファイルがプリフェッチされているかどうかを確認するにはスキームが true 事実上、これは次の手順にすぎません: (ページ A は showcase_d0fbaaef124a8691398704216ccd469a.css を使用しますが、ページ B は使用しないと仮定します)
すべてのキャッシュをクリアします: アドレスに chrome と入力しますbar: //settings/clearBrowserData 開いたら、[キャッシュされた画像とファイル] をチェックし、[閲覧データの消去] をクリックします
ブラウザの現在のキャッシュ リソース リストを表示します: chrome://cache/
2 番目のバージョンも、同じ例に従います
prefetching.html 内の js が実行されると、必然的に大量の js エラーが発生します - 不快に見えます ~
1. すべてのページで実行される js があります:
// 打开一个iframe,下载之后页面可能需要的js/csssetTimeout(function() { var lastOpenTime = 0; var nowTime = (new Date()).getTime(); try { lastOpenTime = window.localStorage.getItem('staticIframeOpenTime'); } catch (e) {} if (lastOpenTime > 0 && (nowTime - lastOpenTime < 24 * 3600 * 1000)) { // 24小时打开一次iframe return; } var iframe = $('<iframe>').css('display', 'none'); iframe .attr('src', 'https://youzan.com/common/prefetching.html') .appendTo(document.body); try { window.localStorage.setItem('staticIframeOpenTime', nowTime); } catch (e) {}}, 3000);// 延时3秒钟加载prefetching.html
2. prefetching.html のリソースは、ダウンロードを許可する方法を見つけますが、ダウンロードは許可しません。基本的に、これらの css/js ファイルは他のタイプのファイルとしてロードされます。最後に、記事「実行せずに CSS/JavaScript をプリロードする」を参照すると、prefetching.html に js ファイルをロードするコードは次のようになります。プリロードされた js ファイルを実行せずにダウンロードするだけ、prefetching.html の読み込みを遅らせる、localstorage レコードの助けを借りて prefetching.html を 1 日 1 回だけロードすることで、バージョン 1 の 3 つの問題は基本的に解決されます。
効果と問題点
サイト全体でモバイルページを立ち上げてから、平均読み込み時間が0.15秒短縮されました。最初の画面時間のデータはありませんが、かなりの収入になるはずです
しかし、このバージョンのリリース後、ページのプリフェッチ中にアニメーションが一時停止することが判明し、最終的にはオブジェクトの読み込みによるものであることが判明しました (この具体的な理由は詳細には調査されていません)。ページは携帯電話でアクセスされ、基本的に Webkit カーネル (Image メソッド) なので、代わりに Image を使用してすべての JS をロードすることにしました。
3 番目のバージョン、完璧です
このバージョンでは、2 番目のバージョンの一時停止アニメーションの問題の解決に加えて、DNS プリフェッチも追加されています。この部分の背景とアイデアについては、私の他の記事「プリロード シリーズ」を参照してください。 1:DNSプリフェッチの正しい利用姿勢》。
<!DOCTYPE html> <html> <head> <?php // dns prefething here ?> <link rel="dns-prefetch" href="//youzan.com/"> ... <?php // css prefething here ?> <link rel="stylesheet" href="//su.yzcdn.cn/v2/build_css/stylesheets/wap/showcase_d0fbaaef124a8691398704216ccd469a.css"> ...</head> <body> <?php // js prefething here ?> <script type="text/javascript"> (function(){ window.onload = function () { var i = 0, max = 0, preloadJs = [ 'js文件路径', ... ]; for (i = 0, max = preloadJs.length; i < max; i += 1) { new Image().src = preloadJs[i]; } }; })(); </script></body> </html>
注意哦,重点来咯! 尽早加载css是减少首屏时间的关键( 引申阅读 ), 直接把css inline到html里 是个不错的方案。但是,这种方案的缺点是无法充分利用浏览器缓存。所以,我们尝试在现有的File Prefetching 的基础上,再进一步,让首次访问足够快(用css line),后续访问又能利用起浏览器缓存。
我们对一部分重点页面的css文件改用类似加载js的方式去加载,并在加载成功的回调里加一条cookie记录标示该css文件已经被下载。这样在后端输出html的时候,可以根据cookie的信息知道这几个css文件是不是已经在浏览器里cache住了。如果是则正常输出一个
标签。如果不是,说明用户是第一次访问这个页面,则直接把css文件的内容inline到html里以求最快出首屏。当然,也会出现从cookie上看客户端已经cache了某个css文件,但实际上没有的情况,由于这种情况下html里输出的还是一个link标签,并不会影响正常的流程。
相关代码大概是这样的,需要的朋友可以参考下:
var loadCss = function(key, url) { var image = new Image(); var date = new Date(); date.setTime(+date + 1 * 86400000); // 因为下载的不是图片,实际触发的是onerror事件 image.onload = image.onerror = function () { document.cookie = key + '=' + url.slice(url.indexOf('build_css')) + ';path=/;domain=.koudaitong.com;expires=' + date.toGMTString(); }; image.src = url;}preloadCss = { key1: '文件路径', key2: '文件路径2' ...}for (var key in preloadCss) { loadCss(key, preloadCss[key]);}
在做 File Prefetching 的过程当中,每一个版本的优化都是不同的人在做的:
A起了个头 ->
B改进到能上线的标准 ->
发现有问题,C改进了它 ->
D又在这个基础上做出了最后一个版本。
这种感觉非常好:)