最新博客站点:欢迎来访

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. C# ADO.NET 面向对象

    ADO.NET跟面向对象的结合 把面向对象跟数据库连接用 在项目里面创建一个新的文件夹   名字为App_Code 在这个App_Code里面创建几个类 主要为拆分问题,标上序号,先干什么在干什么 实 ...

  2. Java虚拟机之栈帧

    写在前面的话:Java虚拟机是一门学问,是众多Java大神们的杰作,由于我个人水平有限,精力有限,不能保证所有的东西都是正确的,这里内容都是经过深思熟虑的,部分引用原著的内容,讲的已经很好了,不在累述 ...

  3. Django组件——cookie与session

    一.会话跟踪技术 1.什么是会话跟踪技术 可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应. 在JavaWeb中,客户向某一服务器发出第一个请求开始,会话就开始了,直 ...

  4. MySQL 修改数据表中的字段的字符编码

    1.查询 MySQL 的版本: SELECT VERSION(); 2.查询 MySQL 当前使用的字符集: SHOW VARIABLES LIKE '%character%'; 3.查询指定数据库的 ...

  5. Drupal Module Hooks

    Drupal is a Content Management System. Drupal is also deeply, deeply weird. While systems like Magen ...

  6. 爬虫入门之爬取策略 XPath与bs4实现(五)

    爬虫入门之爬取策略 XPath与bs4实现(五) 在爬虫系统中,待抓取URL队列是很重要的一部分.待抓取URL队列中的URL以什么样的顺序排列也是一个很重要的问题,因为这涉及到先抓取那个页面,后抓取哪 ...

  7. Java Hotspot client模式和server模式的区别

    当虚拟机运行在-client模式的时候,使用的是一个代号为C1的轻量级编译器, 而-server模式启动的虚拟机采用相对重量级,代号为C2的编译器. C2比C1编译器编译的相对彻底,服务起来之后,性能 ...

  8. 【Leetcode】【Easy】Remove Nth Node From End of List

    Given a linked list, remove the nth node from the end of list and return its head. For example, Give ...

  9. shell中和RDA中的alert日志中文乱码

    客户端字符集无法识别中文,只能下载到本机使用nodepad++查看

  10. 2017软件测试_HW1_最近遇到的编程问题

     最近遇到的错误:我对着网页源代码编写了一段爬虫语句,运行没有提示有错误,而且 可以抓取到全部的数据,但是不能按照要求将这些数据分到制定的位置. 发现问题原因:我把抓取到的字段对着网页源码看了一下,发 ...