The problem: scripts block downloads

Let’s first take a look at what the problem is with the script
downloads. The thing is that before fully downloading and parsing a
script, the browser can’t tell what’s in it. It may contain
document.write() calls which modify the DOM tree or it may even
contain location.href and send the user to a whole new page. If that
happens, any components downloaded from the previous page may never be
needed. In order to avoid potentially useless downloads, browsers first
download, parse and execute each script before moving on with the queue
of other components waiting to be downloaded. As a result, any script on
your page blocks the download process and that has a negative impact on
your page loading speed.

Here’s how the timeline looks like when downloading a slow JavaScript
file (exaggerated to take 1 second). The script download (the third row
in the image) blocks the two-by-two parallel downloads of the images
that follow after the script:

图片 1

Here’s the example to test yourself.

如果在页面上展示了一个数据表格,而用户想把这个表格导出为Excel文件,那么在要求不高的情况下,可以不通过服务器生成表格,而是直接利用JavaScript的Blob和Object
URL特性将表格导出。不过,丑话说在前头,这篇随笔中利用了Excel能打开HTML文档的特性,所以导出的表格实际上是一个HTML文档,并且其扩展名只能为.xls,而不能是.xlsx,否则Excel无法打开。(不过确实见过使用JavaScript生成真正Excel文件的方案,这里暂不提及。)

确保代码尽量简洁

确保代码尽量简洁

Problem 2: number of downloads per hostname

Another thing to note in the timeline above is how the images following
the script are downloaded two-by-two. This is because of the restriction
of how many components can be downloaded in parallel. In IE <= 7 and
Firefox 2, it’s two components at a time (following the HTTP 1.1 specs),
but both IE8 and FF3 increase the default to 6.

You can work around this limitation by using multiple domains to host
your components, because the restriction is two components per
hostname
. For more information of this topic check the article
“Maximizing Parallel Downloads in the Carpool Lane” by Tenni Theurer.

The important thing to note is that JavaScripts block downloads across
all hostnames
. In fact, in the example timeline above, the script is
hosted on a different domain than the images, but it still blocks them.

实现代码如下,包含HTML页面和JavaScript脚本:

  不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大量的JavaScript代码。只有必要的时候用一下。只有确实能改善用户体验的时候用一下。

  不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大量的JavaScript代码。只有必要的时候用一下。只有确实能改善用户体验的时候用一下。

Scripts at the bottom to improve user experience

As Yahoo!’s Performance rules advise, you should put the scripts at the
bottom of the page, towards the closing </body> tag. This doesn’t
really make the page load faster (the script still has to load), but
helps with the progressive rendering of the page. The user perception is
that the page is faster when they can see a visual feedback that there
is progress.

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <meta charset="utf-8" />
    <style>
        /* 此样式仅用于浏览器页面效果,Excel不会分离表格边框,不需要此样式 */
        table {
            border-collapse: collapse;
        }
    </style>
</head>
<body>
    <!-- 设置border="1"以显示表格框线 -->
    <table border="1">
        <!-- caption元素可以生成表标题,其单元格列跨度为表格的列数 -->
        <caption>学生成绩表</caption>
        <tr>
            <!-- 可以使用rowspan和colspan来合并单元格 -->
            <th rowspan="2">编号</th>
            <th rowspan="2">学号</th>
            <th rowspan="2">姓名</th>
            <th rowspan="2">性别</th>
            <th rowspan="2">年龄</th>
            <th colspan="3">成绩</th>
        </tr>
        <tr>
            <th>语文</th>
            <th>数学</th>
            <th>英语</th>
        </tr>
        <tr>
            <td>1</td>
            <td>2016001</td>
            <td>张三</td>
            <td>男</td>
            <td>13</td>
            <td>85</td>
            <td>94</td>
            <td>77</td>
        </tr>
        <tr>
            <td>2</td>
            <td>2016002</td>
            <td>李四</td>
            <td>女</td>
            <td>12</td>
            <td>96</td>
            <td>84</td>
            <td>89</td>
        </tr>
    </table>

    <a>导出表格</a>

    <script>
        // 使用outerHTML属性获取整个table元素的HTML代码(包括<table>标签),然后包装成一个完整的HTML文档,设置charset为urf-8以防止中文乱码
        var html = "<html><head><meta charset='utf-8' /></head><body>" + document.getElementsByTagName("table")[0].outerHTML + "</body></html>";
        // 实例化一个Blob对象,其构造函数的第一个参数是包含文件内容的数组,第二个参数是包含文件类型属性的对象
        var blob = new Blob([html], { type: "application/vnd.ms-excel" });
        var a = document.getElementsByTagName("a")[0];
        // 利用URL.createObjectURL()方法为a元素生成blob URL
        a.href = URL.createObjectURL(blob);
        // 设置文件名,目前只有Chrome和FireFox支持此属性
        a.download = "学生成绩表.xls";
    </script>
</body>
</html>

  尽量减少DOM访问

  尽量减少DOM访问

Non-blocking scripts

It turns out that there is an easy solution to the download blocking
problem: include scripts dynamically via DOM methods. How do you do
that? Simply create a new <script> element and append it to the
<head>:

var js = document.createElement('script');

js.src = 'myscript.js';

var head = document.getElementsByTagName('head')[0];

head.appendChild(js);

Here’s the same test from above, modified to use the script node
technique. Note that the third row in the image takes just as long to
download, but the other resources on the page are loading
simultaneously:

图片 2

Test example

As you can see the script file no longer blocks the downloads and the
browser starts fetching the other components in parallel. And the
overall response time is cut in half.

效果如图:

  使用JavaScript访问DOM元素很容易,代码更容易阅读,但是速度很慢。下面介绍几个要点:限制使用JavaScript来修饰网页布局,把针对访问元素的引用缓存起来。有时,当你的网站依赖大量的DOM改动时,就应该考虑限制你的标记。这是改用HTML5、舍弃那些原来的XHTML和HTML4的一个充分理由。你可以查看DOM元素的数量,只要在Firebug插件的控制台中输入:document.getElementsByTagName(‘*’).length。

  使用JavaScript访问DOM元素很容易,代码更容易阅读,但是速度很慢。下面介绍几个要点:限制使用JavaScript来修饰网页布局,把针对访问元素的引用缓存起来。有时,当你的网站依赖大量的DOM改动时,就应该考虑限制你的标记。这是改用HTML5、舍弃那些原来的XHTML和HTML4的一个充分理由。你可以查看DOM元素的数量,只要在Firebug插件的控制台中输入:document.getElementsByTagName(‘*’).length。

Dependencies

A problem with including scripts dynamically would be satisfying the
dependencies. Imagine you’re downloading 3 scripts and three.js
requires a function from one.js. How do you make sure this works?

Well, the simplest thing is to have only one file, this way not only
avoiding the problem, but also improving performance by minimizing the
number of HTTP requests (performance rule #1).

If you do need several files though, you can attach a listener to the
script’s onload event (this will work in Firefox) and the
onreadystatechange event (this will work in IE). Here’s a blog post
that shows you how to do this. To be fully cross-browser compliant, you
can do something else instead: just include a variable at the bottom of
every script, as to signal “I’m ready”. This variable may very well be
an array with elements for every script already included.

图片 3

  压缩代码

  压缩代码

Using YUI Get utility

The YUI Get Utility makes it easy for you to use script includes. For
example if you want to load 3 files, one.js, two.js and three.js,
you can simply do:

var urls = ['one.js', 'two.js', 'three.js'];

YAHOO.util.Get.script(urls);

YUI Get also helps you with satisfying dependencies, by loading the
scripts in order and also by letting you pass an onSuccess callback
function which is executed when the last script is done loading.
Similarly, you can pass an onFailure function to handle cases where
scripts fail to load.

var myHandler = {

onSuccess: function(){

alert(':))');

},

onFailure: function(){

alert(':((');

}

};


var urls = ['1.js', '2.js', '3.js'];

YAHOO.util.Get.script(urls, myHandler);

Again, note that YUI Get will request the scripts in sequence, one after
the other. This way you don’t download all the scripts in parallel, but
still, the good part is that the scripts are not blocking the rest of
the images and the other components on the page. Here’s a good example
and tutorial on using YUI Get to load scripts.

YUI Get can also include stylesheets dynamically through the method
YAHOO.util.Get.css() [example].

Which brings us to the next question:

打开下载的文件:

  要提供经过压缩的JavaScript页面,最有效的办法就是先用JavaScript压缩工具对你的代码压缩一下,这种压缩工具可以压缩变量和参数名称,然后提供因而获得的代码,使用了gzip压缩。

  要提供经过压缩的JavaScript页面,最有效的办法就是先用JavaScript压缩工具对你的代码压缩一下,这种压缩工具可以压缩变量和参数名称,然后提供因而获得的代码,使用了gzip压缩。

And what about stylesheets?

Stylesheets don’t block downloads in IE, but they do in Firefox.
Applying the same technique of dynamic inserts solves the problem. You
can create dynamic link tags like this:

var h = document.getElementsByTagName('head')[0];

var link = document.createElement('link');

link.href = 'mycss.css';

link.type = 'text/css';

link.rel = 'stylesheet';

h.appendChild(link);

This will improve the loading time in Firefox significantly, while not
affecting the loading time in IE.

Another positive side effect of the dynamic stylesheets (in FF) is that
it helps with the progressive rendering. Usually both browsers will wait
and show blank screen until the very last piece of stylesheet
information is downloaded, and only then they’ll start rendering. This
behavior saves them the potential work of re-rendering when new
stylesheet rules come down the wire. With dynamic <link>s this is not
happening in Firefox, it will render without waiting for all the styles
and then re-render once they arrive. IE will behave as usual and wait.

But before you go ahead and implement dynamic <link> tags, consider
the violation of the rule of separation of concerns: your page
formatting (CSS) will be dependent on behavior (JS). In addition,
this problem is going to be addressed in future Firefox versions.

图片 4

  是的,我没有压缩我的main.js,但你要检查有没有未经压缩的任何jQuery插件,别忘了压缩。下面我列出了压缩方面的几个方案。

  是的,我没有压缩我的main.js,但你要检查有没有未经压缩的任何jQuery插件,别忘了压缩。下面我列出了压缩方面的几个方案。

Other ways?

There are other ways to achieve the non-blocking scripts behavior, but
they all have their drawbacks.

Method Drawback
Using defer attribute of the script tag IE-only, unreliable even there
Using document.write() to write a script tag
  1. Non-blocking behavior is in IE-only
  2. document.write is not a recommended coding practice
XMLHttpRequest to get the source then execute with eval().
  1. eval() is evil”
  2. same-domain policy restriction
XHR request to get the source, create a new script tag and set its content
  1. more complex
  2. same-domain policy
Load script in an iframe
  1. complex
  2. iframe overhead
  3. same-domain policy

使用开发者工具检查a元素,就能大致明白blob URL的工作原理:

  ◆
YUI压缩工具(jQuery开发团队就使用它),初学者指南

  ◆
YUI压缩工具(jQuery开发团队就使用它),初学者指南

Future

Safari and IE8 are already changing the way scripts are getting loaded.
Their idea is to download the scripts in parallel, but execute them in
the sequence they’re found on the page. It’s likely that one day this
blocking problem will become negligible, because only a few users will
be using IE7 or lower and FF3 or lower. Until then, a dynamic script tag
is an easy way around the problem.

<a href="blob:http://localhost:52347/0ead79dc-1896-4a53-b1f1-dfbafff4e953" download="学生成绩表.xls">导出表格</a>

(
(

(
(

Summary

  • Scripts block downloads in FF and IE browsers and this makes your
    pages load slower.
  • An easy solution is to use dynamic <script> tags and prevent
    blocking.
  • YUI Get Utility makes it easier to do script and style includes and
    manage dependencies.
  • You can use dynamic <link> tags too, but consider the separation
    of concerns first.

problem: scripts block downloads Let’s first
take a look at what the problem is with the script downloads. The thing
is that before fully downloading and parsing a script, the…

如果想通过按钮导出文件,可以在按钮的点击事件中创建a元素,配置其属性并触发其点击事件。不过在FireFox中,需要先将创建的a元素放入body中,否则无法下载。

  ◆ Dean Edwards
Packer()

  ◆ Dean Edwards
Packer()

  ◆
JSMin()

  ◆
JSMin()

  GZip压缩:其背后的想法是,缩短在浏览器和服务器之间传送数据的时间。缩短时间后,你得到标题是Accept-Encoding:
gzip,deflate的一个文件。不过这种压缩方法有一些缺点。它在服务器端和客户端都要占用处理器资源(以便压缩和解压缩),还要占用磁盘空间。

  GZip压缩:其背后的想法是,缩短在浏览器和服务器之间传送数据的时间。缩短时间后,你得到标题是Accept-Encoding:
gzip,deflate的一个文件。不过这种压缩方法有一些缺点。它在服务器端和客户端都要占用处理器资源(以便压缩和解压缩),还要占用磁盘空间。

  避免eval():虽然有时eval()会在时间方面带来一些效率,但使用它绝对是错误的做法。eval()导致你的代码看起来更脏,而且会逃过大多数压缩工具的压缩。

  避免eval():虽然有时eval()会在时间方面带来一些效率,但使用它绝对是错误的做法。eval()导致你的代码看起来更脏,而且会逃过大多数压缩工具的压缩。

  加快JavaScript装入速度的工具:Lab.js

  加快JavaScript装入速度的工具:Lab.js

  有许多出色的工具可以加快JavaScript装入的速度。值得一提的一款工具是Lab.js。

  有许多出色的工具可以加快JavaScript装入的速度。值得一提的一款工具是Lab.js。

  借助LAB.js(装入和阻止JavaScript),你就可以并行装入JavaScript文件,加快总的装入过程。此外,你还可以为需要装入的脚本设置某个顺序,那样就能确保依赖关系的完整性。此外,开发者声称其网站上的速度提升了2倍。

  借助LAB.js(装入和阻止JavaScript),你就可以并行装入JavaScript文件,加快总的装入过程。此外,你还可以为需要装入的脚本设置某个顺序,那样就能确保依赖关系的完整性。此外,开发者声称其网站上的速度提升了2倍。

  使用适当的CDN

  使用适当的CDN

  现在许多网页使用内容分发网络(CDN)。它可以改进你的缓存机制,因为每个人都可以使用它。它还能为你节省一些带宽。你很容易使用ping检测或使用Firebug调试那些服务器,以便搞清可以从哪些方面加快数据的速度。选择CDN时,要照顾到你网站那些访客的位置。记得尽可能使用公共存储库。

  现在许多网页使用内容分发网络(CDN)。它可以改进你的缓存机制,因为每个人都可以使用它。它还能为你节省一些带宽。你很容易使用ping检测或使用Firebug调试那些服务器,以便搞清可以从哪些方面加快数据的速度。选择CDN时,要照顾到你网站那些访客的位置。记得尽可能使用公共存储库。

  面向jQuery的几个CDN方案:

  面向jQuery的几个CDN方案:

  ◆

  ◆

  ◆

  ◆

  •
(mt)。

  •
(mt)。

  网页末尾装入JavaScript

  网页末尾装入JavaScript

  如果你关注用户,用户因互联网连接速度慢而没有离开你的网页,这是一个非常好的做法。易用性和用户放在首位,JavaScript放在末位。这也许很痛苦,但是你应该有所准备,有些用户会禁用JavaScript。可以在头部分放置需要装入的一些JavaScript,但是前提是它以异步方式装入。

  如果你关注用户,用户因互联网连接速度慢而没有离开你的网页,这是一个非常好的做法。易用性和用户放在首位,JavaScript放在末位。这也许很痛苦,但是你应该有所准备,有些用户会禁用JavaScript。可以在头部分放置需要装入的一些JavaScript,但是前提是它以异步方式装入。

  异步装入跟踪代码

  异步装入跟踪代码

  这一点非常重要。我们大多数人使用谷歌分析工具(Google
Analytics)来获得统计数据。这很好。现在看一下你把你的跟踪代码放在哪里。是放在头部分?还是说它使用document.write?然后,如果你没有使用谷歌分析工具异步跟踪代码,那也只能怪你自己。

  这一点非常重要。我们大多数人使用谷歌分析工具(Google
Analytics)来获得统计数据。这很好。现在看一下你把你的跟踪代码放在哪里。是放在头部分?还是说它使用document.write?然后,如果你没有使用谷歌分析工具异步跟踪代码,那也只能怪你自己。

  这就是谷歌分析工具异步跟踪代码的样子。我们必须承认,它使用DOM,而不是使用document.write,这可能更适合你。它可以在网页装入之前检测到其中一些事件,这非常重要。现在想一想这种情况,你的网页甚至还没有装入,所有用户都关闭了网页。已找到了解决页面浏览量错失的办法。

  这就是谷歌分析工具异步跟踪代码的样子。我们必须承认,它使用DOM,而不是使用document.write,这可能更适合你。它可以在网页装入之前检测到其中一些事件,这非常重要。现在想一想这种情况,你的网页甚至还没有装入,所有用户都关闭了网页。已找到了解决页面浏览量错失的办法。

复制代码 代码如下:

复制代码 代码如下:

var _gaq = _gaq || [];
_gaq.push([‘_setAccount’, ‘UA-XXXXXXX-XX’]);
_gaq.push([‘_trackPageview’]);
(function() {
var ga = document.createElement(‘script’); ga.type = ‘text/JavaScript’;
ga.async = true;
ga.src = (‘https:’ == document.location.protocol ? ” :
”) + ‘.google-analytics.com/ga.js’;
var s = document.getElementsByTagName(‘script’)[0];
s.parentNode.insertBefore(ga, s);
})();

var _gaq = _gaq || [];
_gaq.push([‘_setAccount’, ‘UA-XXXXXXX-XX’]);
_gaq.push([‘_trackPageview’]);
(function() {
var ga = document.createElement(‘script’); ga.type = ‘text/JavaScript’;
ga.async = true;
ga.src = (‘https:’ == document.location.protocol ? ” :
”) + ‘.google-analytics.com/ga.js’;
var s = document.getElementsByTagName(‘script’)[0];
s.parentNode.insertBefore(ga, s);
})();

  没有使用谷歌分析工具?这不是问题,今天的分析工具提供商大多允许你使用异步跟踪。

  没有使用谷歌分析工具?这不是问题,今天的分析工具提供商大多允许你使用异步跟踪。

  Ajax优化

  Ajax优化

  Ajax请求对你网站的性能有重大影响。下面我介绍关于Ajax优化的几个要点。

  Ajax请求对你网站的性能有重大影响。下面我介绍关于Ajax优化的几个要点。

  缓存你的ajax

  缓存你的ajax

  先看一下你的代码。你的ajax可以缓存吗?是的,它依赖数据,但是你的ajax请求大多应该可以缓存。在jQuery中,你的请求在默认情况下已被缓存,不包括script和jsonp数据类型。

  先看一下你的代码。你的ajax可以缓存吗?是的,它依赖数据,但是你的ajax请求大多应该可以缓存。在jQuery中,你的请求在默认情况下已被缓存,不包括script和jsonp数据类型。

  针对Ajax请求使用GET

  针对Ajax请求使用GET

  POST类型请求要发送两个TCP数据包(先发送标题,然后发送数据)。GET类型请求只需要发送一个数据包(这可能取决于你的cookie数量)。所以,当你的URL长度不到2K,你又想请求一些数据时,不妨使用GET。

  POST类型请求要发送两个TCP数据包(先发送标题,然后发送数据)。GET类型请求只需要发送一个数据包(这可能取决于你的cookie数量)。所以,当你的URL长度不到2K,你又想请求一些数据时,不妨使用GET。

  使用ySlow

  使用ySlow

  说到性能,ySlow既简单,又极其有效。它可以对你的网站进行评分,显示哪些方面需要改正,以及应关注哪些方面。

  说到性能,ySlow既简单,又极其有效。它可以对你的网站进行评分,显示哪些方面需要改正,以及应关注哪些方面。

  另外支一招:把你的JavaScript打包成PNG文件

  另外支一招:把你的JavaScript打包成PNG文件

  设想一下:把你的JS和CSS添加到图片的末尾,然后用CSS来裁切,通过一次HTTP请求来获得应用程序中所需的所有信息。

  设想一下:把你的JS和CSS添加到图片的末尾,然后用CSS来裁切,通过一次HTTP请求来获得应用程序中所需的所有信息。

  我最近找到了这个方法。它基本上把你的JavaScript/css数据打包成PNG文件。之后,你可以拆包,只要使用画布API的getImageData()。此外,它非常高效。你可以在不缩小数据的情况下,多压缩35%左右。而且是无损压缩!我得指出,对比较庞大的脚本来说,在图片指向画布、读取像素的过程中,你会觉得有“一段”装入时间。
英文原文:

  我最近找到了这个方法。它基本上把你的JavaScript/css数据打包成PNG文件。之后,你可以拆包,只要使用画布API的getImageData()。此外,它非常高效。你可以在不缩小数据的情况下,多压缩35%左右。而且是无损压缩!我得指出,对比较庞大的脚本来说,在图片指向画布、读取像素的过程中,你会觉得有“一段”装入时间。
英文原文:

不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大…

您可能感兴趣的文章:

  • JavaScript
    AJAX之惰性载入函数
  • 利用函数的惰性载入提高javascript代码执行效率
  • JavaScript
    函数惰性载入的实现及其优点介绍
  • JavaScript性能优化之函数节流(throttle)与函数去抖(debounce)
  • javascript日期处理函数,性能优化批处理
  • Javascript中产生固定结果的函数优化技巧
  • javascript教程:关于if简写语句优化的方法
  • nodejs的10个性能优化技巧
  • JavaScript也谈内存优化
  • js 优化次数过多的循环
    考虑到性能问题
  • javascript
    for循环从入门到偏门(效率优化+奇特用法)
  • JS性能优化笔记搜索整理
  • JS优化与惰性载入函数实例分析

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图