JS动态加载脚本并执行回调操作


Posted in Javascript onAugust 24, 2016

关于在javascript里面加载其它的js文件的问题可能很多人都遇到过,但很多朋友可能并不知道怎么判断我们要加载的js文件是否加载完成,如果没有加载完成我们就调用文件里面的函数是不会成功的。本文讲解怎么在js中加载其它js文件并在加载完成后执行回调函数。 

我们可以动态的创建 <script> 元素,然后通过更改它的 src 属性来加载脚本,但是怎么知道这个脚本文件加载完成了呢,因为我们有些函数需要在脚本加载完成生效后才能开始执行。
经过对网络上资源的搜索,我发现在 IE 浏览器中可以使用 <script> 元素的 onreadystatechange 来监控加载状态的改变,并通过判断它的 readyState 是 loaded 或 complete 来判断脚本是否加载完成。而非 IE 浏览器可以使用 onload 来直接判断脚本是否加载完成。 

一个简单的实现过程看上去是下面这样的: 

//IE下:
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.onreadystatechange = function() {
  if(this.readyState == "loaded" || this.readyState == "complete"){
    alert("加载成功啦!");
  }
}
script.setAttribute("src",scripts[i]);

//Opera、FF、Chrome等:
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.onload = function() {
  alert("加载成功啦!");
}
script.setAttribute("src",scripts[i]);

原理很简单,根据这两个简单的原理,我们进行一些修改,我把改成了两个函数,分别是串行加载和并行加载脚本。  

当传一个包含多个JS文件路径的数组时,串行加载函数从第一个脚本文件加载开始,每加载成功一个便开始加载下一个脚本文件,全部加载完成后执行回调函数。而并行加载是一开始便加载全部的脚本文件,也就是他们从同一点开始加载,当全部加载完成后,执行回调函数。 

经过测试,这两个函数兼容目前的所有主流浏览器。 

/** 
 * 串联加载指定的脚本
 * 串联加载[异步]逐个加载,每个加载完成后加载下一个
 * 全部加载完成后执行回调
 * @param array|string 指定的脚本们
 * @param function 成功后回调的函数
 * @return array 所有生成的脚本元素对象数组
 */

function seriesLoadScripts(scripts,callback) {
  if(typeof(scripts) != "object") var scripts = [scripts];
  var HEAD = document.getElementsByTagName("head").item(0) || document.documentElement;
  var s = new Array(), last = scripts.length - 1, recursiveLoad = function(i) { //递归
    s[i] = document.createElement("script");
    s[i].setAttribute("type","text/javascript");
    s[i].onload = s[i].onreadystatechange = function() { //Attach handlers for all browsers
      if(!/*@cc_on!@*/0 || this.readyState == "loaded" || this.readyState == "complete") {
        this.onload = this.onreadystatechange = null; this.parentNode.removeChild(this); 
        if(i != last) recursiveLoad(i + 1); else if(typeof(callback) == "function") callback();
      }
    }
    s[i].setAttribute("src",scripts[i]);
    HEAD.appendChild(s[i]);
  };
  recursiveLoad(0);
}
 

/**
 * 并联加载指定的脚本
 * 并联加载[同步]同时加载,不管上个是否加载完成,直接加载全部
 * 全部加载完成后执行回调
 * @param array|string 指定的脚本们
 * @param function 成功后回调的函数
 * @return array 所有生成的脚本元素对象数组
 */

function parallelLoadScripts(scripts,callback) {
  if(typeof(scripts) != "object") var scripts = [scripts];
  var HEAD = document.getElementsByTagName("head").item(0) || document.documentElement, s = new Array(), loaded = 0;
  for(var i=0; i<scripts.length; i++) {
    s[i] = document.createElement("script");
    s[i].setAttribute("type","text/javascript");
    s[i].onload = s[i].onreadystatechange = function() { //Attach handlers for all browsers
      if(!/*@cc_on!@*/0 || this.readyState == "loaded" || this.readyState == "complete") {
        loaded++;
        this.onload = this.onreadystatechange = null; this.parentNode.removeChild(this); 
        if(loaded == scripts.length && typeof(callback) == "function") callback();
      }
    };
    s[i].setAttribute("src",scripts[i]);
    HEAD.appendChild(s[i]);
  }
}

在这里是把 <script> 标签动态的插入到页面中的 <head> 标签内部,并且加载完成后标签元素会被自动移除。
细心的你还会发现,这里使用了一种称作条件编译的方法作为表达式(!/*@cc_on!@*/0)来判断是否非 IE 浏览器,关于条件编译并不是本文的重点,有兴趣的您可以上网查找相关资料进行学习。 

这两个函数的使用方法: 这里我们声明了一个数组变量,里面包含了两个远程的JS文件地址(当然 <script> 标签调用脚本是支持跨域的): 

var scripts = [ 
  "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
  "http://wellstyled.com/files/jquery.debug/jquery.debug.js"
];

//这两个文件分别是 jQuery 1.4.的库文件和 jQuery Debug 插件
//然后你可以使用下面的方法调用并在成功后执行回调了。

seriesLoadScripts(scripts,function(){ 

  /*
  debug = new $.debug({ 
    posTo : { x:'right', y:'bottom' },
    width: '480px',
    height: '50%',
    itemDivider : '<hr>',
    listDOM : 'all'
  }); 

  */
  alert('脚本加载完成啦');
});

 这里使用的是串联加载的函数,当然你也可以使用并联加载函数,这可以根据情况使用,建议每下一个脚本对上一个脚本有依赖性的使用串联加载,否则使用并联,因为原理上并联要比串联快那么些。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
学习ExtJS 访问容器对象
Oct 07 Javascript
js操作textarea 常用方法总结
Dec 03 Javascript
Jquery实现搜索框提示功能示例代码
Aug 13 Javascript
不依赖Flash和任何JS库实现文本复制与剪切附源码下载
Oct 09 Javascript
jquery实现简单文字提示效果
Dec 02 Javascript
JS组件系列之Bootstrap table表格组件神器【终结篇】
May 10 Javascript
javascript RegExp 使用说明
May 21 Javascript
Javascript动画效果(3)
Oct 11 Javascript
Thinkphp5微信小程序获取用户信息接口的实例详解
Sep 26 Javascript
解析vue data不可以使用箭头函数问题
Jul 03 Javascript
JSON获取属性值方法代码实例
Jun 30 Javascript
JavaScript原生数组函数实例汇总
Oct 14 Javascript
利用jsonp跨域调用百度js实现搜索框智能提示
Aug 24 #Javascript
归纳下js面向对象的几种常见写法总结
Aug 24 #Javascript
BootStrap iCheck插件全选与获取value值的解决方法
Aug 24 #Javascript
js友好的时间返回函数
Aug 24 #Javascript
JS转换HTML转义符的方法
Aug 24 #Javascript
gulp-uglify 与gulp.watch()配合使用时报错(重复压缩问题)
Aug 24 #Javascript
JS判断是否在微信浏览器打开的简单实例(推荐)
Aug 24 #Javascript
You might like
PHP实现文件上传下载实例
2016/10/18 PHP
PHP编程快速实现数组去重的方法详解
2017/07/22 PHP
ubutu 16.04环境下,PHP与mysql数据库,网页登录验证实例讲解
2017/07/20 PHP
php依赖注入知识点详解
2019/09/23 PHP
jQuery 1.2.x 升? 1.3.x 注意事项
2009/05/06 Javascript
jquery ajax属性async(同步异步)示例
2013/11/05 Javascript
JS动态修改iframe高度和宽度的方法
2015/04/01 Javascript
jQuery实现点击水纹波动动画
2016/04/10 Javascript
require.js+vue开发微信上传图片组件
2016/10/27 Javascript
微信小程序 UI与容器组件总结
2017/02/21 Javascript
2种在vue项目中使用百度地图的简单方法
2018/09/28 Javascript
JS实现的贪吃蛇游戏案例详解
2019/05/01 Javascript
vue3.0 搭建项目总结(详细步骤)
2019/05/20 Javascript
pm2启动ssr失败的解决方法
2019/06/29 Javascript
node实现爬虫的几种简易方式
2019/08/22 Javascript
解决layer 关闭当前弹窗 关闭遮罩层 input值获取不到的问题
2019/09/25 Javascript
vue 使用lodash实现对象数组深拷贝操作
2020/09/10 Javascript
详解ES6中class的实现原理
2020/10/03 Javascript
在HTML中使用JavaScript的两种方法
2020/12/24 Javascript
[01:00]DOTA2 store: Collection of Artisan's Wonders
2015/08/12 DOTA
[00:12]DAC SOLO赛卫冕冠军 VG.Paparazi灬展现SOLO技巧
2018/04/06 DOTA
[03:21]【TI9纪实】Old Boys
2019/08/23 DOTA
Python实现动态添加类的属性或成员函数的解决方法
2014/07/16 Python
用Python实现通过哈希算法检测图片重复的教程
2015/04/02 Python
python实现每天自动签到领积分的示例代码
2020/08/18 Python
python 通过exifread读取照片信息
2020/12/24 Python
台湾最大网路书店:博客来
2018/03/18 全球购物
Omio葡萄牙:全欧洲低价大巴、火车和航班搜索和比价
2019/02/09 全球购物
计算机数据库专业职业生涯规划书
2014/02/08 职场文书
股东协议书
2014/04/14 职场文书
部门群众路线教育实践活动对照检查材料思想汇报
2014/10/07 职场文书
python使用pywinauto驱动微信客户端实现公众号爬虫
2021/05/19 Python
Redis字典实现、Hash键冲突及渐进式rehash详解
2021/09/04 Redis
vue如何使用模拟的json数据查看效果
2022/03/31 Vue.js
python 闭包函数详细介绍
2022/04/19 Python
阿里面试Nacos配置中心交互模型是push还是pull原理解析
2022/07/23 Java/Android