6
  • defer和asnyc(只对外部文件有效)

    • defer 在页面完成解析时执行代码,这个属性表明脚本在执行时不会影响页面的构造,在元素中设置这个属性相当于告诉浏览器立即下载但延迟执行

    • async 相对于页面其他部分异步执行脚本,一般的script标签都是会阻塞页面执行的,没有加上async属性的标签会阻塞后面的标签的解析。一般用在不需要操作dom元素的脚本上,例如一些统计代码(跟页面执行逻辑无关的,不涉及dom操作的),可以避免因长时间加载而呈现白屏现象

  • script中有或没有它们的区别

    • script中没有defer和async,会立刻加载并执行

    • script中有async没有defer时,会与渲染后续文档元素并行加载,加载完自动执行

    • script中有defer没有async时,后续文档元素渲染会与脚本文件加载并行,但是执行所有元素解析完成之后,在DOMContentLoaded之前执行

QQ图片20160929092409.png

https://segmentfault.com/q/10... 这个回答很棒

  • 但是红宝书中有这样一句话:HTML5规范要求脚本执行应该按照脚本出现的先后顺序执行,但在现实生活中,延迟脚本并不一定按照顺序执行,也不一定会在DOMContentLoaded事件中触发前执行,因此最好只包含一个延迟脚本。因此上图第三点说法有欠缺

Paste_Image.png

未解决问题:所有浏览器都兼容,那么为什么没有看到别人在用呢?

查了一下,网易有在用,浏览器兼容还是有点小问题,and业务需求

  • script是可以并行下载的,这里应该是指放在head中的script标签,不会阻塞其他script标签,但是仍然会阻塞其他资源下载,例如图片。尽管脚本的下载过程中不会相互影响,但页面仍然要等到所有js代码下载并完成执行才能继续。-- 《高性能的js》

并行下载测试

Paste_Image.png

  • 建议放在body的底部

  • 每个script标签初始化都会阻塞页面渲染,在解析html页面过程中每遇到一个script标签都会因执行脚本而导致一定的延时

  • 尽管单个较大的js文件只请求一次http,但是这样会导致锁死浏览器一段时间,解决方案除了上面所说的defer之外还可以动态创建标签加入head中,可以通过onload事件来监听脚本加载是否完毕,ie下通过readystatechange事件

function loadScript(url, callback) {

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

    if ( script.readyState ) { // IE

        script.onreadystatechange = function(){

            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);

}

Obeing
665 声望108 粉丝

努力地成为一只小牛