最新博客站点:欢迎来访

1. 浏览器加载

    (1) 同步加载

在网页中,浏览器加载js文件的方式是通过<script>标签。如下所示:

//内嵌脚本
<script type="text/javacript">
// code here!
</script>
//加载外部脚本
<script type="text/javascript src="path/demo.js"></script>

<script>标签很方便,只要加入后,浏览器便可读取并运行,但是在读取的时候,浏览器是按照<script>标签的出现顺序,读取Javascript文件,然后立即运行,导致在多个文件相互依赖的情况下,依赖性最小的文件必须放在最前面,依赖性最大的必须放在最后面,否则代码会报错,这一点,想必大家在使用bootstrap的时候都深有体会。另一方面,浏览器采用同步模式加载<script>标签,也就是说,页面会等待JavaScript文件加载完成,然后再运行后面的代码。当存在很多个<script>标签时,浏览器无法同时读取,必须读完一个再读取另一个,造成读取时间大大延长,页面响应缓慢,影响用户体验。同步模式又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当前加载完成,才能进行下一步操作,所以默认同步执行才是安全的。但这样如果js中有输出document内容、修改DOM、重定向等行为,就会造成阻塞。所以一般建议把<script>标签放在<body>结尾处,这样能减少页面阻塞。

    (2)异步加载

为了解决这一问题,ES5中采用了DOM方法,动态加载JavaScript脚本文件

function loadScript(url) {
var script = document.createElement("script");
script.type="text/javascript";
script.src=url;
document.body.appendChild(script);
}

这种方式通过创建一个新的<script>标签,并设置其src属性,异步读取javacript文件

这样不会造成页面阻塞,但会有另一个问题,如果其他脚本文件依赖于它,此时无法保证此脚本什么时候能够载入完毕。

另一种加载方式是利用defer和async属性,使脚本异步加载。渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令。defer和async的区别是: defer要等到整个页面在内存中正常渲染结束(DOM结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完成,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。即defer是渲染完再执行,async是下载完就执行。另外,如果有多个defer脚本,会按照它们在页面中出现的顺序加载,而多个async脚本是不能保证加载顺序的。

        IE9及以下版本在延迟实现方面存在一些相当糟糕的错误,导致执行顺序无法保证。 如果你需要支持<= IE9,我建议不要使用defer,如果执行顺序很重要,请包含没有属性的脚本。
<script src="path/demo.js" defer></script>
<script src="path/demo.js" async></script>

如何选用defer和async。如果使用的script是个模块,并且不依赖任何其它script文件时使用async;如果该脚本依赖其它script或则被其它script依赖,就使用defer;倘若脚本文件很小且被一个async script依赖,就使用内嵌script把该文件放在所有async script前面。

另外一种方法是onload事件的异步加载。

(function(){
if(window.attachEvent) {
window.attachEvent("load", asyncLoad);
} else if(window.addEventListener) {
window.addEventListener("load", asyncLoad);
} else {
window.onload = asyncLoad;
}
var asyncLoad = function() {
var script = document.createElement("script");
script.type="text/javascript";
script.async = true;
script.src = ('https:'==document.location.protocol ? 'https://ssl' : 'http:www') + '.baidu.com/demo.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(script, s);
};
)();

这种方法是把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件的触发问题。

由于Javascript的动态性,还有很多异步加载方法:XHR Injection、XHR eval、Script In Iframe、document.write("<script type='text/javascript' src=' '")等;

XHR注入:通过XMLHttpRequest来获取Javascript,然后创建一个script元素插入到DOM结构中。ajax请求成功后设置script.text为请求成功后返回的responseText.

var createXHR  = function() {
var obj;
if(window.XMLHttpRequest)
obj = new XMLHttpRequest();
else
obj = new ActiveObject("Microsoft.XMLHTTP");
return obj;
};
var xhr = createXML();
xhr.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == 200) {
var script = document.createElement("script");
script.text = xhr.requestText;
document.getElementsByTagName("head")[0].appendChild(script);
}
}

XHR eval(): 与XHR Injection对responseText的执行方式不同,直接把responseText放在eval()函数里面执行。

var createXHR  = function() {
var obj;
if(window.XMLHttpRequest)
obj = new XMLHttpRequest();
else
obj = new ActiveObject("Microsoft.XMLHTTP");
return obj;
};
var xhr = createXML();
xhr.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == 200) {
eval(xhr.responseText);
$('#btn').click(function() {
alert($(this).text());
});
}
}

Script In Iframe: 在父窗口插入一个iframe元素,然后再iframe中执行加载JS的操作。

var insertJS = function(){
alert($);
};
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;//获取iframe中的window
doc.open();
doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>");
doc.close();

2. 延迟加载

有些JS代码在某些情况下需要使用,并不是页面初始化的时候就要用到。延迟加载就是为解决这个问题。将JS切分成许多模块,页面初始化时只将事件处理程序添加到UI元素上,然后其它JavaScript代码的加载延迟到第一次用户交互或者其他条件需要用到的时候再加载。类似图片的懒加载。这样做的目的是可以渐进式地载入页面,尽可能快地为用户提供目前需要的信息,其余部分的内容可以在用户浏览该页面时在后台载入。

JavaScript的加载分为两个部分:下载和执行脚本,异步加载只解决了下载的问题,但是代码在下载完成后就可能会立即执行,在执行过程中浏览器储与阻塞状态,响应不了任何需求。为了解决JavaScript延迟加载的问题,可以利用异步加载缓存起来,所以不会立即执行,然后在第一次需要的时候再执行。

第二部分内容的载入可以用创建动态脚本的形式:

window.onload = function() {
var script = document.createElement("script");
script.type="text/javascript";
script.src="demo.js";
document.documentElement.firstChild.appendChild("script");
}

3. 按需加载

可以通过创建一个require方法,包含需要加载的脚本名称和附加脚本加载完成后需要执行的回调函数。

function require(file, callback) {
var script = document.getElementsByTagName("script")[0];
var newjs = document.createElement("script"); newjs.onload= function() {
callback();
};
newjs.src=file;
script.parentNode.insertBefore(newjs, script);
}

参考:

https://www.jb51.net/article/107680.htm

http://es6.ruanyifeng.com/#docs/module-loader

Javascript的加载的更多相关文章

  1. 关于javascript模块加载技术的一些思考

    前不久有个网友问我在前端使用requireJs和seajs的问题,我当时问他你们公司以前有没有自己编写的javascript库,或者javascript框架,他的回答是什么都没有,他只是听说像requ ...

  2. 浏览器中Javascript的加载和执行

    在刚学习Javascript时曾对该问题在小组内做个一次StudyReport,发现其中的基础还是值得分析的. 从标题分析,可以加个Javascript的加载和执行分为两个阶段:加载.执行.而加载即浏 ...

  3. Javascript 异步加载详解(转)

    本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy execution),async 属 ...

  4. 该如何理解AMD ,CMD,CommonJS规范--javascript模块化加载学习总结

    是一篇关于javascript模块化AMD,CMD,CommonJS的学习总结,作为记录也给同样对三种方式有疑问的童鞋们,有不对或者偏差之处,望各位大神指出,不胜感激. 本篇默认读者大概知道requi ...

  5. javascript异步加载的三种解决方案

    默认情况javascript是同步加载的,也就是javascript的加载时阻塞的,后面的元素要等待javascript加载完毕后才能进行再加载,对于一些意义不是很大的javascript,如果放在页 ...

  6. Javascript 异步加载详解

    Javascript 异步加载详解 本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy ...

  7. javascript异步加载详解(转)

    本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy execution),async 属 ...

  8. javascript 的加载方式

    本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy execution),async 属 ...

  9. 转: javascript模块加载框架seajs详解

    javascript模块加载框架seajs详解 SeaJS是一个遵循commonJS规范的javascript模块加载框架,可以实现javascript的模块化开发和模块化加载(模块可按需加载或全部加 ...

  10. javascript模块加载框架seajs详解

    SeaJS是一个遵循commonJS规范的javascript模块加载框架,可以实现javascript的模块化开发和模块化加载(模块可按需加载或全部加载).SeaJS可以和jQuery完美集成,使用 ...

随机推荐

  1. javascript获取后台传来的json

    Mvc Razor视图引擎中 <script type="text/javascript"> var _temp = @(new MvcHtmlString(this. ...

  2. Hashtable(哈希表)

    简体字繁体字转化: class Program { static void Main(string[] args) { Hashtable ht = new Hashtable(); ; i < ...

  3. (0!=0)==true? 记一个匪夷所思的问题

    最近换了份工作,公司的开发框架是基于SSH自己搭建的.这个问题是我在解决一个需求的时候遇到的,其实解决这个疑惑的过程也就是读框架源码的过程,特此记录一下. 问题:ba.getState()!=CbBa ...

  4. 编程语言的发展历史剧。(参考https://baijiahao.baidu.com/s?id=1588675986991787716&wfr=spider&for=pc)

    1800年 约瑟夫·玛丽·雅卡尔(Joseph Marie Jacquard),设计出人类历史 上首台可设计织布机——雅卡尔织布机,对将来发展出其他可编程机器起了重要作用 1842年 阿达·洛夫莱斯( ...

  5. form中button特殊功能

    描述:写弹窗的时候发现,form中的button,不对它进行什么设置,它会有默认的操作,点击“发送验证码”或者“提交申请”,它都会退出弹窗(取消遮罩层) 解决:button有不同的type属性,只需要 ...

  6. input placeholder 在chrome 浏览器自动填充时,背景色覆盖原有背景图片问题。

    user-block-name, .user-block-pwd { margin-bottom: 10%; text-align: center; position: relative; } .us ...

  7. 转载《学习HTML5 canvas遇到的问题》

    学习HTML5 canvas遇到的问题 1. 非零环绕原则(nonzZero rule) 非零环绕原则是canvas在进行填充的时候是否要进行填充的判断依据. 在判断填充的区域拉一条线出来,拉到图形的 ...

  8. 分享一个好东西(一天精通MongoDB数据库)

    https://pan.baidu.com/s/1o7V5e8U 总共几个小时的视频,看了之后醍醐灌顶.分享出来.

  9. Shader Example

    //测试viewDir对顶点的影响Shader "Example/TestViewDir" { Properties{ _RimColor("Rim Color" ...

  10. python str、int、dict

    一.str print(dir(int))#['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', ...