写在前面

好的书,可能你第一遍并不能领会里面的精魂,当再次细细品评的时候,发现领悟的又是一层新的含义

(这段时间,工作上也不会像从前一样做起来毫不费力,开始有了新的挑战,现在的老大让我既佩服又嫉妒,但真的是打心底里仰慕,希望自己有朝一日能过到他那个高度)

既然现在还达不到那个层次,就好好堆砖吧,当砖堆到一定高度也自然会上一个小台阶。

脚本位置

脚本会阻塞页面渲染,直到它们全部下载并执行完成,页面才会继续渲染。页面只有加载并执行完前面一个script外部文件才会去加载下面一个script标签。

在IE8、FireFox3.5、Safari4、和Chrome2才开始允许并行下载JavaScript文件,也就是说从这个时候开始script标签在下载外部资源时不会阻塞其它script标签,但是javascript下载的过程仍然会阻塞其它资源的下载(比如图片),尽管脚本的下载过程不会互相影响,但页面仍然必须等待所有的javascript代码下载并执行完成才能继续

这也就是为什么推荐将所有的script标签尽可能放到body标签的底部,以尽量减少对整个页面下载的影响

组织脚本

由于每个script标签初始下载时都会阻塞页面渲染,所以减少页面包含的script标签数量能改善页面性能(这不仅仅针对外链脚本,内嵌脚本的数量也同样限制)

把一段内嵌脚本放在引用外链样式表的link标签之后会导致页面阻塞去等待样式表的下载,浏览器这样做是为了确保内嵌脚本在执行时能获得最精确的样式信息,因此,建议永远不要把内嵌脚本紧跟在link标签后面

把多个文件合并为一个,可以减少性能消耗 

无阻塞脚本

无阻塞脚本也就是在页面加载完成后才加载javaScript代码,有多种方式来实现

1、script标签有一个扩展属性defer,defer属性指明本元素所含脚本不会修改dom,因此代码能安全的延迟执行(但是它并非所有浏览器兼容)

带有defer属性的script标签可以放置在文档的任何位置,对应的javascript文件将在页面解析到script标签时开始下载,但并不会执行,直到dom加载完成(不仅仅外链脚本,内嵌脚本也一样)

也就是说带有defer属性的javascript文件下载时,它不会阻塞浏览器的其它进程,因此它可以与页面的其它资源并行下载

2、动态脚本元素:因为script元素与页面其它元素没有实质性的差别,利用这点,可以通过js创建script并添加到页面上,这样做的好处在于:无论何时启动下载,文件的下载和执行过程都不会阻塞页面其它进程,你甚至可以把代码放到页面head区域而不会影响页面其它部分

通常来讲,把新创建的script标签添加到head标签里比添加到body里更保险 ,尤其是在页面加载过程中执行代码时更是如此,因为body中的内容没有全部加载完成,这时... 

使用动态脚本节点下载文件后,返回的代码通常会立即执行(这样也会有一个问题,所以你必须确保代码中需要调用的接口都已经准备就绪)

script元素提供一个readyState属性,它有5种取值

  • uninitialized初始状态
  • loading开始下载
  • loaded下载完成
  • interactive数据完成下载但尚不可用
  • complete所有数据已准备就绪
        /*
        *@desc:兼容所有浏览器的动态加载script
        *@param:url  script的src
        *@param:callback  回调函数
        */
        function loadScript(url, callback) {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            if (script.readyState) {//IE
                script.onreadystatechange = function () {
                    //IE在标识最终状态readyState的值时并不一致,有时到达loaded状态而不到达complete,有时候甚至不经过loaded就到达complete状态,
                    //所以靠谱的方式就是同时检查这两种状态
                    if (script.readyState = 'loaded' || script.readyState == 'complete') {
                        script.onreadystatechange = null;
                        callback();
                    }
                }
            } else {
                script.onload = function () {
                    callback();
                }
            }
            script.src = url;
            document.getElementsByTagName('head')[0].appendChild(script);            
        }

  使用如上代码的方法动态加载js,浏览器不会保证执行的顺序

3、使用XMLHttpRequest(XHR),也就是通过创建一个XHR通过,然后用它下载js文件,最后动态创建script元素将代码注入页面中

        var xhr = new XMLHttpRequest();
        xhr.open('get', 'file1.js', true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {//2XX表示有效响应  304表示从缓存中读取
                    var script = document.createElement('script');
                    script.type = 'text/javascript';
                    script.text = xhr.responseText;
                    document.body.appendChild(script);
                }
            }
        }
        xhr.send(null);

使用XHR的特性:

  • 下载javascript代码,但不立即执行
  • 同样的代码在所有浏览器中都能正常使用
  • 请求的js文件必须与所请求的页面牌相同的域

推荐的无阻塞模式

    <script>
        /*
        *@desc:兼容所有浏览器的动态加载script
        *@param:url  script的src
        *@param:callback  回调函数
        */
        function loadScript(url, callback) {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            if (script.readyState) {//IE
                script.onreadystatechange = function () {
                    //IE在标识最终状态readyState的值时并不一致,有时到达loaded状态而不到达complete,有时候甚至不经过loaded就到达complete状态,
                    //所以靠谱的方式就是同时检查这两种状态
                    if (script.readyState = 'loaded' || script.readyState == 'complete') {
                        script.onreadystatechange = null;
                        callback();
                    }
                }
            } else {
                script.onload = function () {
                    callback();
                }
            }
            script.src = url;
            document.getElementsByTagName('head')[0].appendChild(script);
        }
        //将loadScript函数直接嵌入页面,从而避免产生一次http请求
        loadScript('theRest.js', function () {
            //加载初始化页面所需的剩下的代码
            //好处1)确保js执行过程中不会阻塞页面其它内容的显示
                //2)当第二个js文件完成下载时,应用所需的所有dom结构已创建完毕,并做好了交互的准备,从而避免了需要另一个事件
        });
    </script>
View Code

相关文章: