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 相关文章推荐
JavaScript中变量声明有var和没var的区别示例介绍
Sep 15 Javascript
node.js中的console.log方法使用说明
Dec 09 Javascript
iScroll中事件点击触发两次解决方案
Mar 11 Javascript
在Node.js应用中使用Redis的方法简介
Jun 24 Javascript
jQuery解决input超多的表单提交
Aug 10 Javascript
jquery+CSS3模拟Path2.0动画菜单效果代码
Aug 31 Javascript
基于Bootstrap实现Material Design风格表单插件 附源码下载
Apr 18 Javascript
JavaScript基于自定义函数判断变量类型的实现方法
Nov 23 Javascript
AngularJS实现表单元素值绑定操作示例
Oct 11 Javascript
js实现贪吃蛇游戏 canvas绘制地图
Sep 09 Javascript
解决vue scoped html样式无效的问题
Oct 24 Javascript
关于vue中如何监听数组变化
Apr 28 Vue.js
利用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判断字符以及字符串的包含方法属性
2008/08/30 PHP
PHP 开发环境配置(Zend Studio)
2010/04/28 PHP
php支持中文字符串分割的函数
2015/05/28 PHP
PHP迭代器和迭代的实现与使用方法分析
2018/04/19 PHP
Yii redis集合的基本使用教程
2020/06/14 PHP
PHP var关键字相关原理及使用实例解析
2020/07/11 PHP
jQuery 插件 将this下的div轮番显示
2009/04/09 Javascript
基于jquery可配置循环左右滚动例子
2011/09/09 Javascript
JS烟花背景效果实现方法
2015/03/03 Javascript
JS鼠标拖拽实例分析
2015/11/23 Javascript
理解javascript中Map代替循环
2016/02/26 Javascript
详细探究ES6之Proxy代理
2016/07/22 Javascript
webpack进阶——缓存与独立打包的用法
2017/08/02 Javascript
Webpack框架核心概念(知识点整理)
2017/12/22 Javascript
echarts实现词云自定义形状的示例代码
2019/02/20 Javascript
浅谈layui里的上传控件问题
2019/09/26 Javascript
《javascript设计模式》学习笔记一:Javascript面向对象程序设计对象成员的定义分析
2020/04/07 Javascript
vue+animation实现翻页动画
2020/06/29 Javascript
Vue+axios封装请求实现前后端分离
2020/10/23 Javascript
python按照多个字符对字符串进行分割的方法
2015/03/17 Python
简单介绍Ruby中的CGI编程
2015/04/10 Python
讲解Python中if语句的嵌套用法
2015/05/14 Python
python使用Plotly绘图工具绘制水平条形图
2020/03/25 Python
django fernet fields字段加密实践详解
2019/08/12 Python
CSS3实现瀑布流布局与无限加载图片相册的实例代码
2016/12/22 HTML / CSS
海滩咖啡馆:Beach Cafe
2018/02/02 全球购物
捷克家居装饰及图书音像购物网站:Velký košík
2018/04/16 全球购物
北美女性服装零售连锁店:maurices
2019/06/12 全球购物
日常奢侈品,轻松购物:Verishop
2019/08/20 全球购物
Skechers越南官方网站:来自美国的运动休闲品牌
2021/02/22 全球购物
学生励志演讲稿
2014/01/06 职场文书
出生证明公证书
2014/04/09 职场文书
幼儿园六一儿童节活动方案
2014/08/26 职场文书
2014年宣传部个人工作总结
2014/12/06 职场文书
永远是春天观后感
2015/06/12 职场文书
Python爬虫:从m3u8文件里提取小视频的正确操作
2021/05/14 Python