博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【转】在网页中异步加载javascript
阅读量:6152 次
发布时间:2019-06-21

本文共 3535 字,大约阅读时间需要 11 分钟。

hot3.png

前端工程师都知道script标签会阻塞网页上其他资源的加载。有时候这种阻塞是必要的,因为javascript可能会改变页面结构,进而对后续的资源(css,js)的作用产生影响。但是,当我们能够识别那些对页面结构不产生影响的javascript并且不希望阻塞其他资源时,我们就需要认真的研究一下,javascript异步加载的方式了。

1. 并行的下载脚本

(1) XHR eval

通过XHR技术我们也可以异步地获取js脚本,并通过eval()执行。

var xhrobj = getXHROject();getXHROject.onreadystatechange = function(){    if(xhrObj.readyState ==4 && 200 == xhrObj.status){      eval(xhrObj.responseText);  }};xhrObj.open(‘GET’,’A.js’,true)xhrOjb.send(‘’);

由于XHR请求不能跨域,所以脚本必须和主页部署在相同的域中,脚本可并行下载,而且不阻塞其他资源,但是无法保证多个脚本的执行顺序。

(2) script dom element

我们也可以直接在浏览器中插入script dom节点。

var scriptElem = document.createElement(‘script’);document.getElementsByTagName(‘head’)[0].appendChild(scriptElem);

这种方式允许跨域加载js脚本,不阻塞其他资源下载。只有 Firefox 和 Opera 保证脚本按文档中出现的顺序执行,其他浏览器需要工程师自己在代码层面实现执行顺序的控制。Requirjs就是这样实现的。

(3) document write script tag

document.write("");

注意script Tag和script dom的区别,scritp Tag可以保证多个脚本并行加载,但是会阻塞其他资源并行下载。这种方式可以保证脚本按文档中出现的顺序执行

(4) defer和async属性

目前大多数浏览器已经defer和async属性。

1. 如果 async="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)2. 如果不使用 async 且 defer="defer":脚本将在页面完成解析时执行3. 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本

async="async"不会阻塞其他资源,但是无法保证脚本的执行顺序。defer="defer"阻塞其他资源的加载,并且可以保证脚本的执行顺序,但是要到页面解析完成后才开始执行脚本。

这么多种异步加载javascript脚本的方式,各有利弊,接下来研究一下如何控制脚本之间执行的顺序。

2.脚本的执行顺序

(1)保证行内脚本和外部脚本的执行顺序

当外部脚本按常规方式加载时,它会阻塞行内脚本的执行,可以保证顺序。但是脚本通过上述的几种方式异步加载时,就无法保证行内脚本和异步脚本之间的顺序。下面就讲解一下保证行内脚本和外部脚本保证执行顺序的技术。

[1].硬编码回调

如果web开发者能够控制外部脚本,可以在外部脚本回调行内脚本。

[2]onlode事件

添加script dom节点时,监听加载事件,当脚本成功加载时调用callback(外部脚本)函数。

//行内函数function callback(){    Console.log(‘calllback’);}//异步加载函数function loadScript(url, callback){    var script = document.createElement ("script")    script.type = "text/javascript";    if (script.readyState){ //IE        script.onreadystatechange = function(){            if (script.readyState == "loaded" || script.readyState == "complete"){                script.onreadystatechange = null;                callback();            }        };    } else { //Others        script.onload = function(){            callback();        };    }    script.src = url;    document.getElementsByTagName("head")[0].appendChild(script);}//控制行内脚本和外部脚本的执行顺序loadScript('a.js',callback);

[3]定时器

通过定时检查外部脚本的相应变量是否定义,可以判断外部脚本是否加载并执行成功。

这三种方法都可以保证行内脚本和外部脚本之间的执行顺序。其实最难的是保证多个外部脚本之间的执行顺序,这也是我们接下来要看的内容。

(2)保证多个外部脚本之间的执行顺序

[1]. 同域中的脚本

对于同域中的多个外部脚本,可以使用XHR的方式加载脚本,并通过一个队列来控制脚本的执行顺序。

[2]对于不同域的脚本

script dom element 可以异步脚本脚本,不阻塞其他资源,并且在firefox和opera可以保证执行顺序;而document write script 可以异步加载脚本,会阻塞其他资源,在所有浏览器都可以保证执行顺序。因此我们可以根据浏览器选择以上两种方案来控制 不同域的脚本的执行顺序。

');              if(onload){                if(elem.addEventListener){//others                    elem.addEventListener(window,'load',onload);                }else if(elem.attachEvent){ //IE                    elem.addEventListener(window,'onload',onload);                }            }        }         //根据浏览器选择浏览器加载js的方式        loadScript: function(url,onload){                if(-1 != navigator.userAgent.idexOf('Firefox') ||                   -1 != navigator.userAgent.indexOf('Opera')){                    //当浏览器为firefox和opera时通过Script Dom Element 保证脚本执行顺序                        DomTag.script.loadScriptDomElement(url,onload);                 }else{                    //当为其他浏览器时,通过document write Script保证脚本执行顺序。此时脚本的加载会阻塞其他资源,这是一种折衷                        DomTag.script.loadScriptDomWrite(url,onload);                }        }  }ScriptLoader.script.loadScript('A.js',initA);ScriptLoader.script.loadScript('B.js',initB);

 

 

转载地址 https://foio.github.io/javascript-async/

转载于:https://my.oschina.net/zimingforever/blog/1550734

你可能感兴趣的文章
7.对象创建型模式-总结
查看>>
1、块:ion-item
查看>>
【论文阅读】Classification of breast cancer histology images using transfer learning
查看>>
移动端处理图片懒加载
查看>>
jQuery.on() 函数详解
查看>>
谈缓存和Redis
查看>>
【转】百度地图api,根据多点注标坐标范围计算地图缩放级别zoom自适应地图
查看>>
用户调研(补)
查看>>
ExtJS之开篇:我来了
查看>>
☆1018
查看>>
oracle 去掉空格
查看>>
6.13心得
查看>>
Runtime类
查看>>
eclipse decompiler
查看>>
记一个搜索网盘资源的网站
查看>>
jdk1.7和jdk1.8的String的getByte方法的差异
查看>>
java父子进程通信
查看>>
Android ADB server didn't ACK * failed to start daemon * 简单有效的解决方案
查看>>
Olap学习笔记
查看>>
Codeforces Round #431 (Div. 1)
查看>>