Table of Contents
第一个版本,简单粗暴有点痛
验证
操作指引:
第二个版本,依样画葫芦
效果和问题
第三个版本,完美
上线后,丝丝润滑无痛无痒,完美
第四个版本,再进一步,可以做更多
总结
TODO
Home Web Front-end HTML Tutorial 预加载系列二:让File Prefetching丝丝润滑无痛无痒_html/css_WEB-ITnose

预加载系列二:让File Prefetching丝丝润滑无痛无痒_html/css_WEB-ITnose

Jun 24, 2016 am 11:29 AM

所谓 File Prefetching 就是在一个页面加载成功后,默默去预加载后续可能会被访问到的页面的资源。前端资源预加载其实没啥新鲜的,我们倒腾这个事情的过程却是很有有意思也很有启发性。

第一个版本,简单粗暴有点痛

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>  
Copy after login

2、 在每个页面加入一个iframe(一般通过base模板统一加),这样每个页面打开的时候都会加载上面这个页面。假设上面的页面的url是 https://xxx.com/common/prefetching.html 那么我们每个页面底部都有这么一行代码:

<iframe src="https://youzan.com/common/prefetching.html" sytle="display:none;"></iframe>  
Copy after login

验证

要验证某个file prefetching的方案是否真的有效,无非就是以下几步: (假设A页面使用了 showcase_d0fbaaef124a8691398704216ccd469a.css ,而B页面不会)

  1. 让chrome终端打开的时候cache功能依旧有效
  2. 清空所有本地cache
  3. 打开B页面,在控制台Networking里看prefetching.html以及附属的资源文件是否被下载了
  4. 打开A页面,注意:是在地址栏里输入A的网址然后回车,不要打开A页面后习惯性地按Command/Ctrl+R来刷新,不出意外,我们会看到如下图这样的结果: 这说明,这2个css文件是从cache里读的。如果Command/Ctrl+R来刷新页面,我们会看到这样的结果: 两者的差别是,Command/Ctrl+R的时候,浏览器会从cache里找该静态文件,如果找到了,会根据上次请求这个文件时得到的 cache-control 信息判断该静态文件是否已经过期了,如果没有,会以 if-modified-since 、 Etag 等信息作为 request headers 向服务器请求这个文件,服务器如果认为文件没有变过,会返回Http code为304,浏览器于是直接读cache。具体不展开啦,可以看 《HTTP caching 》 和 《Understanding HTTP/304 Responses》 。

操作指引:

让chrome终端打开的时候cache功能依旧有效 :Chrome终端的配置里把 Disable cache (while DevTools is open) 的勾选去掉

清空所有cache :地址栏里输入 chrome://settings/clearBrowserData 打开后勾上 Cached images and files 点 Clear browsing data

查看浏览器当前cache的资源列表 : chrome://cache/

第二个版本,依样画葫芦

目前看来,上面这个 File Prefeching 的方案是有效的。不过这种是最简陋的试验版,存在几个问题:

  1. prefetching.html 里的js会被执行,然后不可避免地会有一堆js错误 —— 看着难受~
  2. 通过iframe 加载 prefetching.html 会影响到当前页面相关资源的加载速度
  3. 每次打开页面都会加载一次 prefetching.html,虽然里面的静态文件都已经在第一次打开的时候被cache住了不会重复下载,但无谓多一个请求终究是没必要。

于是,我们上线使用的版本是这样的:

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
Copy after login

2、prefetching.html 里的资源想办法让他下载但不执行,基本上都是把这些css/js文件当做其他类型的文件来加载,最后参照了 《Preload CSS/JavaScript without execution》 这篇文章,prefetching.html 中加载js文件的代码大概是这样的:

<script type="text/javascript">    window.onload = function () {    var i = 0,      max = 0,      o = null,      preload = [        '需要预加载的文件路径'      ],      isIE = navigator.appName.indexOf('Microsoft') === 0;    for (i = 0, max = preload.length; i < max; i += 1) {      if (isIE) {        new Image().src = preload[i];        continue;      }      // firefox不兼容 new Image().src 这种方式,所以除了IE都借用 object 来加载      o = document.createElement('object');      o.data = preload[i];      o.width  = 0;      o.height = 0;      document.body.appendChild(o);    }  };</script>  
Copy after login

通过 对预加载的js文件只下载不执行 、 延时加载prefetching.html 、 借助localstorage的记录一天只加载一次prefetching.html ,基本上解决了版本一的3个问题。

效果和问题

移动页面全站上线后,平均loaded时间减少了0.15s,首屏时间没有数据,不过收益应该是可观的

不过,这个版本上线后,我们发现页面在prefetching的时候会假死,最后定位到是因为object加载js导致的(具体为什么会这样还没细究),考虑到我们主要的页面都是在手机端访问的,基本上都是webkit内核(Image的方式在firefox中不兼容也不甚关系),所以我们决定改用Image来加载所有JS。

第三个版本,完美

这个版本除了解决第二个版本的假死问题,还加入了dns-prefetch,关于这部分的背景和思路可以参考我另外一篇文章: 《预加载系列一:DNS Prefetching 的正确使用姿势》 。

<!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>  
Copy after login

上线后,丝丝润滑无痛无痒,完美

第四个版本,再进一步,可以做更多

注意哦,重点来咯! 尽早加载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]);}
Copy after login

总结

在做 File Prefetching 的过程当中,每一个版本的优化都是不同的人在做的:

A起了个头 ->

B改进到能上线的标准 ->

发现有问题,C改进了它 ->

D又在这个基础上做出了最后一个版本。

这种感觉非常好:)

TODO

  1. 其实还有一类资源可以加到这个prefetching.html里,那就是常用的图片,不过我们还没这么做。
  2. 我们现在全部移动web页只使用一个prefetching.html,并还没有针对不同的条件进行针对性的的prefetching。
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Difficulty in updating caching of official account web pages: How to avoid the old cache affecting the user experience after version update? Difficulty in updating caching of official account web pages: How to avoid the old cache affecting the user experience after version update? Mar 04, 2025 pm 12:32 PM

The official account web page update cache, this thing is simple and simple, and it is complicated enough to drink a pot of it. You worked hard to update the official account article, but the user still opened the old version. Who can bear the taste? In this article, let’s take a look at the twists and turns behind this and how to solve this problem gracefully. After reading it, you can easily deal with various caching problems, allowing your users to always experience the freshest content. Let’s talk about the basics first. To put it bluntly, in order to improve access speed, the browser or server stores some static resources (such as pictures, CSS, JS) or page content. Next time you access it, you can directly retrieve it from the cache without having to download it again, and it is naturally fast. But this thing is also a double-edged sword. The new version is online,

How do I use HTML5 form validation attributes to validate user input? How do I use HTML5 form validation attributes to validate user input? Mar 17, 2025 pm 12:27 PM

The article discusses using HTML5 form validation attributes like required, pattern, min, max, and length limits to validate user input directly in the browser.

What are the best practices for cross-browser compatibility in HTML5? What are the best practices for cross-browser compatibility in HTML5? Mar 17, 2025 pm 12:20 PM

Article discusses best practices for ensuring HTML5 cross-browser compatibility, focusing on feature detection, progressive enhancement, and testing methods.

How to efficiently add stroke effects to PNG images on web pages? How to efficiently add stroke effects to PNG images on web pages? Mar 04, 2025 pm 02:39 PM

This article demonstrates efficient PNG border addition to webpages using CSS. It argues that CSS offers superior performance compared to JavaScript or libraries, detailing how to adjust border width, style, and color for subtle or prominent effect

What is the purpose of the <datalist> element? What is the purpose of the <datalist> element? Mar 21, 2025 pm 12:33 PM

The article discusses the HTML &lt;datalist&gt; element, which enhances forms by providing autocomplete suggestions, improving user experience and reducing errors.Character count: 159

What is the purpose of the <progress> element? What is the purpose of the <progress> element? Mar 21, 2025 pm 12:34 PM

The article discusses the HTML &lt;progress&gt; element, its purpose, styling, and differences from the &lt;meter&gt; element. The main focus is on using &lt;progress&gt; for task completion and &lt;meter&gt; for stati

How do I use the HTML5 <time> element to represent dates and times semantically? How do I use the HTML5 <time> element to represent dates and times semantically? Mar 12, 2025 pm 04:05 PM

This article explains the HTML5 &lt;time&gt; element for semantic date/time representation. It emphasizes the importance of the datetime attribute for machine readability (ISO 8601 format) alongside human-readable text, boosting accessibilit

What is the purpose of the <meter> element? What is the purpose of the <meter> element? Mar 21, 2025 pm 12:35 PM

The article discusses the HTML &lt;meter&gt; element, used for displaying scalar or fractional values within a range, and its common applications in web development. It differentiates &lt;meter&gt; from &lt;progress&gt; and ex

See all articles