原文:http://www.stevesouders.com/blog/2010/12/15/controljs-part-2/
关于ControlJs一共有三篇文章,这是第二部分。ControlJS是让脚本加载更快的一个模块(a javascript module for making scripts load faster). 三篇文章的结构分别为:
1. async loading [中文翻译:http://ued.ctrip.com/blog/?p=2964]
2. delayed execution [中文翻译:http://ued.ctrip.com/blog/?p=3017]
3. overriding document.write [中文翻译:http://ued.ctrip.com/blog/?p=3111]
ControlJS的目标是让开发者更好的控制脚本的加载。其中的关键是意识到”loading”有两个步骤:下载[download](获取内容)和执行[execution](包括解析).在ControlJS part 1(中文翻译:http://ued.ctrip.com/blog/?p=2964)中,我主要阐述了如何用ControlJS来异步加载脚本。在本篇中,我将讲一讲ControlJS在脚本执行阶段[execution]能做些什么?
The issue with execution
执行阶段的问题关键是:浏览器在解析和执行脚本的时候,它其他什么都干不了。通常的表现就是浏览器的界面无响应,页面渲染被阻止,浏览器中新资源的下载被终止。
执行阶段花费的时间可能比你想象中要长。我无法获取这个阶段具体消耗了多少时间(当然你也可以用dynaTrace Ajax Edition or Speed Tracer来收集这些数据)。如果你进行了大量密集的DOM操作,很容易呈现这种阻塞的情况。如果页面中有大量的脚本,仅仅解析的时间就会消耗很长的时间了。
当然,如果所有的脚本都是必须立即执行来渲染页面的,那么我们能做的也只有停止操作,等待这些脚本执行完毕。不过,久而久之,我们会发现大部分下载的脚本并不是需要立刻执行的。通过Alexa US Top 10 ,你会发现在window load之前,仅有29%的脚本需要被调用。(我用Page Speed‘s的”defer Javascript”的功能来做的调查)。余下的71%的代码是什么情况呢?虽然它们对页面初始渲染没有任何帮助,但是它们仍然被解析并且执行了。在我调查的页面中,平均每个页面下载229kB的脚本。这229kB的是压缩的- 压缩前应该会超过500KB了。比起在页面下载的时候执行那71%的脚本,更好的办法是在页面渲染完毕之后再去执行那些脚本。但是开发者怎么做到呢?
Loading feature code
为了让我们接下去的讨论更简单一些,我们把那29%需要去渲染页面的代码称为”immediate-code”(IC),余下的71%称为”future-code”(FC).FC一般来说是DHTML或者Ajax的功能,例如下拉菜单、弹出对话框、好友邀请……这些代码只有用户操作了某些功能之后才能触发的。
假设你已经成功的将页面的脚本分成了IC和FC.IC的那部分就可以使用async loading capabilities在页面初始化的时候下载。FC的那部分呢,在页面下载的时候也同样的方式下载。然后浏览器会将那些不需要立即使用的代码的解析和执行先锁住。我们不希望在页面初始化的时候就下载那71%的脚本。
当然,还有一个办法,那就是在页面渲染完毕之后,再去下载那些FC. 这些脚本可以在onload的回调函数中进行后台加载。不过即便这些FC在后台加载,在他们解析和执行的时候,浏览器仍然会被“冻住”。如果这个时候用户尝试操作页面,将得不到任何响应。这些没必要的延迟会带来很多麻烦,所以Gmail的移动小组有了他们自己的一套解决办法Gmail mobile team’s way
道理很简单,也就是在用户需要的时候,再去解析和执行future-code。举个例子,当用户首次点击了下拉菜单,那么我们就去解析和执行menu.js。如果用户从来没有用过下拉菜单,那么我们就免去menu.js的不必要的解析执行的开销。不过当用户点击了那个菜单,我们并不希望他们还要等待menu.js的下载-尤其是在手机上。那最好的解决方案就是在后台下载脚本,但是直到用户真正需要的时候再去执行它。
Download now, Execute later
我们接下去看一下ControlJS在这方面能做些什么。我列出了一下的几个例子

Read more »