同步加载和执行JS的情况

在HTML页面的</body>表情之前添加的所有<script>标签,无论是直接嵌入JS代码还是引入外部js代码都是同步执行的,这里的同步执行指的是在加载好和执行完JS代码之前整个浏览器的界面都是阻塞的。

静态加载时

内嵌代码和引入js代码都是同步加载。

动态加载时

通过document.write('<script src="xxx.js"></script>');的方式加入的代码也是同步加载的,但是要注意一点,这里开始加载和解析xxx.js是在执行完成当前的<script>标签之后,所以下面的代码会报错(我们假设test.js中创建了全局的p对象,且该对象存在sayHi的方法):

 <script>
console.log("sync load js");
document.write('<script src="test.js"></script>');
console.log(p.sayHi());
</script>

根据我们说的开始加载和解析xxx.js是在执行完成当前的<script>标签之后,可以把上面的代码转换如下:

 <script>
console.log("sync load js");
console.log(p.sayHi());
</script>
<script src="test.js"></script>

这样必然会出错,如下则可以正常执行:

 <script>
console.log("sync load js");
document.write('<script src="test.js"></script>');
</script>
<script>
console.log(p.sayHi());
</script>

document.write方式同步加载外部js文件无论是内嵌的写法还是写在外部js文件中,效果都是一样的,都会同步加载和执行。

异步加载和执行JS的情况

静态加载时

对于内嵌的JS代码只能同步执行,对于通过<script>标签引入的外部js文件,可以通过设定defer和async两个属性改变为异步加载执行。

defer

代码如下:<script src="xxx.js" defer></script>,该属性在HTML4.01引入,告诉浏览器立即下载该脚本(下载期间不阻塞页面),但是等待遇到</html>标签之后再执行,同时执行顺序按照标签出现顺序进行执行。该脚本的执行一定会在页面的load事件之前。

async

代码如下:<script src="xxx.js" async></script>,该属性在HTML5引入,告诉浏览器立即下载该脚本(下载期间不阻塞页面),但是执行脚本时不能保证按照标签出现顺序执行。该脚本的执行一定会在页面的load事件之前。

最佳实践

由于浏览器的支持不同,所以最好的方法仍然是将<script src="xxx.js"></script>脚本放在页面的最下方引入。

动态加载时

如果我们希望在页面任意时刻动态异步加载js文件,可以通过使用DOM元素创建方法来实现:

 var script = document.createElement("script");
script.type = "text/javascript";
script.src = "xxx.js";
document.getElementsByTagName("head")[0].appendChild(script);

当script元素被添加到页面之后便开始下载脚本文件。该技术的优点是:无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。当script文件下载完成后,返回的代码通常被立即执行(除了FF和Opera,它们将等待此前的所有动态脚本节点执行完毕。)

唯一的问题是我们需要知道动态加载的脚本何时完成加载并可以使用,FF, Opera, Chrome和Safari3+会在节点接收完成后发出一个load事件;IE则是发出一个readystatechange事件,<script>元素有一个readyState属性,它的值随着下载过程而改变。readyState有5种取值:uninitialized(默认状态),loading(下载开始),loaded(下载完成),interactive(下载完成但尚不可用),complete(所有数据已准备好)。

最终的代码如下:

 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 { // FF, Chrome, Opera, ...
script.onload = function() {
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}

如果要加载多个文件,并且要保证顺序,则可以采用将上述函数串联的方式实现。

 loadScript("../scripts/test1.js", function(){
loadScript("../scripts/test2.js", function(){
loadScript("../scripts/test3.js", function(){
test3.print("hi, i'm abc.");
})
});
});

如果觉得这种嵌入的写法太不爽,也可以稍作修改改为Promise的写法。

HTML5学习笔记(二十三):DOM应用之动态加载脚本的更多相关文章

  1. AntDesign vue学习笔记(五)导航菜单动态加载

    一般的后台系统都有一个树形导航菜单,具体实现如下,主要参考https://my.oschina.net/u/4131669/blog/3048416 "menuList": [ { ...

  2. python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码

    python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码 淘宝IP地址库 http://ip.taobao.com/目前提供的服务包括:1. 根据用户提供的 ...

  3. Android 学习笔记之Volley(七)实现Json数据加载和解析...

    学习内容: 1.使用Volley实现异步加载Json数据...   Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...

  4. Redis深入学习笔记(一)Redis启动数据加载流程

    这两年使用Redis从单节点到主备,从主备到一主多从,再到现在使用集群,碰到很多坑,所以决定深入学习下Redis工作原理并予以记录. 本系列主要记录了Redis工作原理的一些要点,当然配置搭建和使用这 ...

  5. Ext JS学习第十天 Ext基础之动态加载JS文件(补充)

    此文用来记录学习笔记: •Ext4.x版本提供的一大亮点就是Ext.Loader这个类的动态加载机制!只要遵循路径规范,即可动态加载js文件,方便把自己扩展组件动态加载进来,并且减轻浏览器的压力. • ...

  6. Javascript学习笔记二——操作DOM

    Javascript学习笔记 DOM操作: 一.GetElementById() ID在HTML是唯一的,getElementById()可以定位唯一的一个DOM节点 二.querySelector( ...

  7. (C/C++学习笔记) 二十三. 运行时类型识别

    二十三. 运行时类型识别 ● 定义 运行时类型识别(Run-time Type Identification, RTTI) 通过RTTI, 程序能够使用基类的指针或引用来检查(check)这些指针或引 ...

  8. Java基础学习笔记二十三 Java核心语法之反射

    类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...

  9. Windows调试学习笔记:(一)WinDBG中加载SOS和CLR

    最近产品环境出现了部分服务器当机情况,虽然重启之后问题就不出现了.但本着彻底解决问题的态度,想要找到root cause.多次尝试Visual Studio失败(可能是代码惊醒了优化和签名)之后,决定 ...

随机推荐

  1. SpringMVC 参数中接收数组、List写法

    本文使用SpringMVC版本: org.springframework:spring-web:4.3.9.RELEASE 写法及说明(示例代码的类上的注解是@RestController,所以不需要 ...

  2. 图解Win7如何手动添加受信任证书

    点击开始—>运行,如下图所示:   弹出“控制台”窗口如下,如下图所示:   点击“文件—添加/删除管理单元”,如下图所示:   选择“证书”,并点击“添加”,如下图所示:   在弹出的窗口上选 ...

  3. chrome配置文件校验初始化隐含參数的逆向

     这篇文章接上一篇文章进一步升华:花了4个小时获得该信息的计算方式 比方在 chrome文件夹下的\Chrome\User Data\Default文件夹下的Secure Preferences,须要 ...

  4. 不可不知的mysql 常用技巧总结

    不可不知的mysql 常用技巧总结 mysql常用命令 mysqld --启动mysql数据库 show databases; -- 查看数据库 use database; -- 选择数据库 show ...

  5. android.telephony.SmsManager.sendMultipartTextMessage

    smsManager.sendMultipartTextMessage(destAddress, null, divideContents, sentIntents, null); next step ...

  6. std::bind 详解及参数解析

    // Bind_std_function.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> ...

  7. python配置文件转dict

    配置文件有很多种,如JSON,properties,conf,xml等. 除非需要跟别的语言进行交互,python本身是完全可以取代所有配置文件的.使用python进行配置可以使用非常灵活地执行一些逻 ...

  8. javascript with关键字简单用法

    1.简要说明         with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性.要给对象创建新的属性,必须明确地引用该对象. 2.语法格式 with(object ...

  9. libpcap详解【转】

    libpcap详解 2010-12-01 22:07 libpcap(Packet Capture Library),即数据包捕获函数库,是Unix/Linux平台下的网络数据包捕获函数库.它是一个独 ...

  10. 老男孩linux实战培训初级班第二次课前考试题

    ################################################################ 本文内容摘录于老男孩linux实战运维培训中心课前考试题(答案部分) ...