欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

ControlJS-脚本的无阻塞下载

shiping1 的头像
  • ContrloJs有大用
    让页面跑的更快些:ControlJS-脚本的无阻塞下载

    Posted at 2011年04月21日 17:14 | 发现 | 查看:3,249

    官方网站:http://stevesouders.com/controljs/

    ControlJS能做什么:

    • 异步加载脚本
    • 脚本延迟执行

    先看两个示例页面:
    下面的 使用了ContrloJs的页面 有大用

    没有使用ControlJS的页面 | 使用了ControlJS的页面

     

    下面三步有大用
    怎样使用ControlJS:

    要把ControlJS应用到您当前的页面中,只需修改三个部分的内容

    #1:引入control.js文件

    control.js本身会以异步的方式加载:

    1
    2
    3
    4
    5
    6
    
    <script type="text/javascript">
    var cjsscript = document.createElement('script');
    cjsscript.src = "control.js";
    var cjssib = document.getElementsByTagName('script')[0];
    cjssib.parentNode.insertBefore(cjsscript, cjssib);
    </script>

    #2:修改页面中需要异步加载脚本的script标签的相关属性

    页面中正常引入外部脚本是下面这样的格式:

    1
    
    <script type="text/javascript" src="main.js"></script>

    把script标签的TYPE属性改成“text/cjs”,SRC属性改成data-cjssrc,像下面这样:

    1
    
    <script type="text/cjs" data-cjssrc="main.js"></script>

    #3:修改内嵌脚本的script标签相关属性:

    1
    2
    3
    
    <script type="text/cjs">
    var name = getName();
    </script>

    ControlJS是怎样工作的?

    ControlJS是通过什么方式让页面中的脚本可以无阻塞的下载执行?在上面的使用方法中你可能已经知道了他的运行方式。它是通过修改页面中 script标签的相关属性,让浏览器识别不了这是脚本文件,然后在页面中查找type属性为“text/cjs” 的script标签,让这些脚本文件以img(在IE和Opera中)或object(除IE和Opera的其他浏览器中)的方式下载,从而实现了无阻 塞,而且,因为这些脚本文件不是通过script标签下载的,它们在下载之后不会立即执行。

    默认情况下,ControlJS是在window对象的onload事件里执行的(也可让它在脚本或某dom对象装载完就执行)。页面里的脚本会按 它出现的先后顺序执行。外部引入的脚本,一旦它伪装成的图片对象或OBJECT对象下载完成,便会以SCRIPT标签的形式嵌入到页面中去,这样这些脚本 就能被解析执行。

    注:其实大多数情况下,把js文件放在页面底部完全能达到相同的效果,这里主要介绍的是他的一种实现方法。

留言板: 4 条评论
  • jason 说:

    这个与jQuery.getScript()有什么区别

     
  • sean 说:

    @jason:getScript只是加载脚本,而ControlJS是控制这个过程。

     
  • Adele Vu 说:

    @jason:getScript只是加载脚本,而ControlJS是控制这个过程。
    +1

     
  • 脚本骆驼 说:

    这种方式不会导致js报错me?

    来自 http://www.rjboy.cn/?p=807
     

    ControlJS - 让脚本加载的更快

    前端性能的提升大部分都是在脚本加载执行上,ControlJS的出现让我们感觉 提高性能如此容易。急不可耐的想把这段时间的研究成果分享出来,希望能给前端俊才们些帮助,同样换回你们的批评指教。非常感谢拔赤师兄的有情支助,让我感 觉前端真是个很有乐趣的领域,因为你知道什么是有意义。

    Steve Souders在2010年12月份发布了ControlJS项目,该项目是让开发者更好的去控制javascript文件的下载和执行,是一个可以让脚本加载更快的组件.从而解决了页面加载脚本的性能问题.

    Steve提出了一个非常具有创造性的思想,就是预先异步下载javascript文件而不执行.这一点得到了很多人的关注与验证。Nicholas Zaka也因ControlJS引发了很多思考,并分析了ControlJSLABjs 的区别所在,详细内容可以阅读Thoughts on script loadersSeparating JavaScript download and execution。Zakas不赞成使用额外的脚本加载库,因为Script loader对浏览器检测的依赖,将是高成本的维护,同时浏览器的发展趋势会为我们解决此类问题。

    但 是对于中国互联网的特殊性来分析,脚本加载库的应用还是非常有必要的。很多ControlJS的思想让我们合理的应用,提升页面脚本加载性能将是非常显 著。Steve专门整理了ControlJS专题,包括一些实例,验证了ControlJS的成功,并使用3篇博闻详细介绍了ControlJS:异步加载延迟执行重写document.write

    1、异步加载

    原 理其实很简单:将script的标签type属性值更改为浏览器无法识别的类型,这样浏览器不会认为这是一个脚本,便不会去下载文件。在页面加载时开始读 取所有type="text/cjs"的script标签(包括内嵌脚本),如果存在"DATA-CJSSRC"属性将创建IMAGE或者OBJECT对 象(依赖浏览器而选择),去异步下载脚本文件并缓存文件,否则便是内嵌脚本需要预存直到需要时使用eval执行,外链需要插入script元素,解析并执 行js内容。

    a>增加ControlJS脚本

    var cjsscript = document.createElement('script');
    cjsscript.src = "control.js";
    var cjssib = document.getElementsByTagName('script')[0];
    cjssib.parentNode.insertBefore(cjsscript, cjssib);

    b>更改页面脚本标签属性

    <script type="text/cjs" data-cjssrc="main.js"><script>
    <script type="text/cjs">
    var name = getName();
    <script>

    c>预加载脚本的过程源码内容如下:

    // Download a script as an image.
    // This puts it in the browser's cache, but doesn't execute it.
    CJS.downloadScriptImage = function(url) {
        var img = new Image();
        img.src = url;
    };
     
     
    // Download a script as an object.
    // This puts it in the browser's cache, but doesn't execute it.
    CJS.downloadScriptObject = function(url) {
        var obj = document.createElement('object');
        obj.data = url;
        document.body.appendChild(obj);
    };


    2、延迟执行

    预加载javascript文件后,在真正出发交互时在进行脚本的执行操作。

    3、重写document.write

    ControlJS 是异步加载所有脚本的,在默认情况下这些异步脚本都是在window.onload解析并执行的,如果此时脚本调用window.write方法,将导致 一个不希望发生的问题,就是整个页面被window.write的输出内容替换,所有页面内容将被删除。问题是由于在docuemnt被加载完后调用 docuemnt.write方法时将会自动去触发document.open,写入任何处于打开状态的doucment都将会会替换整个页面的内容,这是无可厚非的。

    对于现在被开发者深恶痛绝的广告,一般都是使用document.write方法来呈现内容的,然而无法将这些内容异步处理是开发者非常头疼的问题。

    ControlJS 的解决方法便是重写docuemnt.write,执行客户端自定义的方法,便是创建一个dom元素(span),将其插入正在被解析执行的script 标签之前,并且设置SPAN的innerHTML的值为docuemnt.write的内容。由于插入innerHTML里存在script标签时,浏览 器将不会很好的识别,因此ControlJS的做法是查找并提取出url,并在页面动态创建script对象来执行脚本内容。

    但是ControlJS存在一个bug就是没有考虑到如果document.write中的script脚本中再次出现document.write的时候,将无法正确定位到最初的异步script,导致广告内容输出的位子错位。

    以上便是ControlJS的相关内容,在实际项目的应用中肯定还会存在一些问题,就像Steve说的ControlJS虽然有些处理上牵强些,但它仍然是很有价值的,我们怎样能将别人的思想融入到我们自己的项目中才是最重要的,光靠拿来主义理论是没有任何意义的。

    最后总结ControlJS为我们做了什么事:
    1、异步下载所有脚本
    2、同时处理内嵌与外链脚本
    3、延迟脚本的执行直到页面被渲染完
    4、允许脚本只下载不执行
    5、不改变脚本代码,只是简单改变HTML标签属性
    6、解决了异步脚本中存在docuement.write的问题
    7、ControlJS本身是异步加载
     
    标签: javascript
    0
    0
    (请您对文章做出评价)
    « 上一篇:关于非阻塞javascript的真相(The truth about non-blocking JavaScript)
    » 下一篇:Flow view - 被忽视的性能检测,占96%的流量
    posted @ 2011-05-17 16:05 chesihui 阅读(771) 评论(1) 编辑 收藏

      
    #1楼 2013-06-23 20:25 | 不回头  
    在通过object/image预加载后是不是应该替换type属性或建立一个script元素?!

    来自 http://www.cnblogs.com/cheche/archive/2011/05/17/1982706.html


    异步加载:ControlJS让脚本加载更快的一个模块

    2011-12-18 11:28:57  来源:携程UED 作者:小灰灰 

     

    网页制作Webjx文章简介:关于ControlJs的使用和基础讲解.

    关于ControlJs一共有三篇文章,这是第一部分。ControlJS是让脚本加载更快的一个模块(a javascript module for making scripts load faster). 三篇文章的结构分别为:

    1. async loading
    2. delayed execution
    3.overriding document.write
    关 于第一部分的异步加载,这个的关键在于尽快将页面作为html绘制出来,然后再用javascript进行优化,或者说用js进一步渲染。我们看到过很多 网页,展示给用户一片空白,只是因为在等待几百KB的js文件下载、解析、执行,而这些js是用来绘制页面中展示给用户看的DOM元素。

     

    其实上述的情况,很容易理解–但是真正实现改进恐怕就困难的多。好几百KB的js必须要拆散重组。那些通过js来创建网页DOM的逻辑代码必须全部合成到后台的服务器端去生成html。即使使用最新的服务器端JS来实现,也是一项很大的重构工程。

    我又回到了Opera的Delayed Script Execution选项。一旦这个选项生效,js会被搁置起来(move aside),让页面首先进行渲染。而这个选项确实很棒,而且没有网站因为开启了这个选项而导致页面报错的。我也一直持续在和其他浏览器的供应商联系,让 他们也实现这个功能,我迫切的希望开发人员能够尽快的使用上这个选项。

    近些年来,一些网页加速器(例如Aptimize, Strangeloop, FastSoft, CloudFlare, Torbit,和最近的mod_pagespeed)犹如雨后春笋般脱颖而出。他们修改了页面中的HTML标签,用来改善网页的性能。从这些模式中,我摸 索出了一个方法,比起延迟加载页面渲染的JS,我们可以更容易的改变HTML标记来实现。

    于是ControlJS诞生了!

    Controlling download and execution
    ControlJS的目标是让开发员更好的控制JS的加载。关键是要意识到“加载”氛围两个步骤:下载[download](即获取内容)和执行[execution](包含解析).为了更好的性能,这两个步骤有必要分离控制。

    在对网页性能敏感的程序员眼中,如何控制脚本下载是一个很广泛流行的话题。当脚本使用普通的方式(也就是<script src=”" …的形式),脚本会阻塞其他资源的下载(在新版本浏览器中稍微好一些),同时也会阻塞页面的渲染(所有浏览器都有这种情况)。使用异步脚本加载 (asynchronous script loading)的技术在很大程序上缓解了这个问题。我在Even Faster Web Sites中提及过几种异步加载的技术。LABjs 和 HeadJS是提供异步加载的js模块。虽然它们的异步技术解决了脚本下载阶段的阻塞问题,但是并没有解决脚本执行时发生的情况。

    在脚本执行阶段,页面渲染和新资源下载会被阻塞。在如今网页中的脚本越来越多,在脚本执行阶段的阻塞问题就更为严重,尤其是在移动设备上。事实 上,Gmail移动设备组考虑到脚本执行带来的问题,它们完善了new async technique that downloads JavaScript wrapped in comments。这项技术可以使得脚本执行和下载分离。脚本会下载到客户端(在浏览器的缓存中),但是因为它是脚本注释,所以在执行阶段不会阻塞(因为 不会执行)。当用户使用了相关功能的时候,需要某些脚本时,会将注释符号删除,然后eval执行代码。

    Stoyan Stefanov, 一名优秀的性能优化前驱者,最近发布了一篇博文preloading JavaScript without execution.他用IMAGE或者OBJECT(这取决于浏览器)来下载脚本。假设这些脚本可以缓存在客户端中,随后可以使用SCRIPT标签插入 脚本。这个也是在ControlJS中使用的技术。

    ControlJS: how to use it
    使用ControlJS涉及到三个步骤的修改

    修改点#1:添加control.js

    我想关于脚本加载模块的使用,最讽刺的地方就在于,加载这些异步脚本加载种子文件是会阻塞页面的。所以从一开始我就必须确认ControlJS是要能被异步加载的。

    var cjsscript = document.createElement('script');
    cjsscript.src = "control.js";
    var cjssib = document.getElementsByTagName('script')[0];
    cjssib.parentNode.insertBefore(cjsscript, cjssib);修改点#2:修改外链的脚本
    下一步就是将所有外链脚本的标签改为ControlJS的形式。原本的脚本引用如下

    <script type="text/javascript" src="main.js"><script>SCRIPT元素的TYPE要改为”text/cjs”,SRC改为“data-cjssrc”,如下:

    <script type="text/cjs" data-cjssrc="main.js"><script>修改点#3 修改内联的脚本
    大多数的页面都会有内联的脚本。这些脚本有一些依赖性:内联脚本中的变量一般依赖于外链的脚本,反之亦然。很重要的一点是:内敛脚本和外链脚本的执行顺序是需要保证的。因此,内联脚本必须改变TYPE属性的值

    <script type="text/javascript">
    var name = getName();
    <script>修改“text/javascript”为”text/cjs”,如下:

    <script type="text/cjs">
    var name = getName();
    <script>这样就ok了!后续的一系列工作就交给ControlJS担心吧!

    ControlJS: how it works
    现在脚本不会阻塞页面了,因为TYPE属性已经改为浏览器无法识别的值了。这也就让ControlJS可以用一种高性能的方法更好的控制脚本加载。让我们大概看看ControlJS是如何运作的呢?当然,你也可以查看control.js 的代码来更详细的了解。

    我们都希望能够尽快的开始下载脚本。因为我们使用IMAGE或者OBJECT来下载脚本,所以它们不会在下载阶段阻塞页面。而且他们并不是作为 SCRIPT下载的,所以它们也不会执行。ControlJS首先找出所有SCRIPT的,并且type为”text/cjs”的标签。如果脚本有一个 DATA-CJSSRC,那么IMAGE(IE和Opera浏览器)或者OBJECT(其他浏览器)就会根据它们的URL动态的创建出来。(你可以查看 Stoyan’s post去了解更详细的内容)。

    一般来说,ControlJS会在window load的时间之后进入执行阶段(当然也可以立刻执行代码或者某个DOM元素加载完毕了)。ControlJS会第二次遍历所有的脚本,确保它们都正确的 出现在页面中。如果这个脚本是一个内联脚本,那么它的代码会被执行。如果这个脚本是一个外链脚本,由IMAGE或者OBJECT动态下载下来的,那么它会 作为一个SCRIPT标签插入到页面中,那么它的代码也会随之解析并且执行。如果IMAGE或者OBJECT并没有下载结束,那么会在一个短暂的时间间隔 之后(a short timeout),重新进入刚才的遍历流程。

    后续的文章中我还会讨论关于document.write的功能,以及跳过执行阶段。这篇中,我们首先来看一个简单的异步加载的例子。

    Async example
    为了能更好展示异步加载的情况,我创建了一个文件,文件顶部包含三个脚本:

    •main.js – 耗费4秒下载
    •一段内联脚本会使用main.js的一个变量
    •page.js – 耗费2秒下载,使用内联脚本的一个变量
    我 让page.js的下载时间比main.js的下载时间短,是为了确认这些脚本可以以正确的顺序执行(尽管page.js下载更快)。我同事也包含了内联 的脚本,因为这也是很多页面的实际情况(例如Google Analytics),但是很多脚本加载器并不支持内联脚本的执行顺序。

    Async withOUT ControlJS是一个基本范例。它使用了最普通的方式加载脚本。可以看一下如下图所示的IE8下的HTTP瀑布图(使用HttpWatch).IE8 比IE6和IE7要好 – 能够使main.js和page.js并行加载。但是所有的IE都会因为脚本加载而阻塞图片的下载。所以images1-4都延迟了。在所有浏览器中,页 面渲染都会被阻塞。在图示中也可以看出,main.js阻塞渲染长达4秒钟(绿色的竖线表示页面开始渲染时间)

     

    Async WITH ControlJS 演示了ControlJS是如何解决由于脚本引发的阻塞问题。不像上面的例子,脚本和图片会并行加载。同时页面渲染也是立刻开始的。如果你同时在浏览器中 演示这两个页面,你会发现ControlJS的页面会快很多。当然,你也发现在下面的图示中多了3个请求,一个是Control.js – 这个是用来异步加载脚本用的代码。另外两个请求时因为main.js和page.js下载了两次。第一次是使用IMAGE或者OBJCET下载,第二次是 使用SCRIPT标签加入页面用来执行代码的。因为main.js和page.js已经存在在浏览器缓存中了,所以他们不需要额外的下载时间。只是短暂的 缓存读取时间(也就是那两根很细的蓝色线)。

    The ControlJS project
    ControlJS是在Apache License下面的开源项目。你可以在ControlJS Google Code project中找到control.js的代码。关于它的讨论可以在ControlJS Google Group.关于上面提到的例子放在我的站点 ControlJS Home Page.我只在大多数的浏览器中测试了,如果要投入到大规模的产品环境中,请进行更详尽的测试。

    Only part1
    这只是ControlJS的第一部分。目前看来似乎已经解决了所有问题了。如果我们只是需要异步加载,那么其他的一些 技术其实也已经实现了。不过我的目标是不能让脚本阻塞页面的渲染。我们就必须面临一个问题,如果处理document.write.另一个方面就是类似于 Gmail的移动组实现的- 下载脚本同时在执行阶段不会阻塞页面渲染。我们会在下面的两篇博文中详细分析。

    来自 http://www.webjx.com/javascript/jsajax-31179.html
普通分类: