javascript动态加载三


Posted in Javascript onAugust 22, 2012

之前两篇都介绍了,通过动态加载JS文件或者说JS模块,是怎么一步一步实现。

首先是通过同步策略来实现模块加载与回调函数之间进行分离,接着是通过异步策略来实现模块加载与回调函数之间进行分离。

这一篇,主要是为了说说怎么优化异步策略,并且实现了随意加载(非任意顺序加载模块),页面Ready之后加载文件。先接一下上一篇遗留下来的问题

1、页面Ready之后进行加载

2、随意添加模块 进行加载

看第一个问题,这个问题其实还是比较简单的,主要是监听页面的DOMContentLoaded事件,这里就不多讲解,网络上搜索,一堆答案,直接上代码。

Using.ready = function(callback){ 
readyList.push(callback); if(document.addEventListener){ 
document.addEventListener("DOMContentLoaded",_ready,false); 
return; 
} 
// for IE 
var domReady = function(){ 
try{ 
document.documentElement.doScroll("left"); 
_ready(); 
}catch(ex){ 
setTimeout(domReady,1); 
return; 
} 
} 
domReady(); 
}

这一段代码中最难以理解的应该就是
document.documentElement.doScroll("left");

这里其实是IE的页面加载完毕事件,简单说就是IE里面标签加载完毕之后,是可以操作Scroll的,那就根据此原理来判断IE中页面是否加载完毕。

里面有一个_ready函数,这个函数就是用来做页面加载完毕之后执行所有加载的函数。贴一下代码

(编辑一下这一段:页面加载完毕Ready函数并不是我们思想中所认为的原生JS的window.load,简单说只是页面中DOM结构的加载完毕,具体信息,可自行百度google之)

var readyList = []; 
var _ready = function(){ 
while(readyList.length > 0){ 
var func = readyList.shift(); 
func(); 
} 
document.removeEventListener("DOMContentLoaded",_ready,false); 
}

下面就是本博文的重点了。还是先看一下代码
Using.asyn = function(callback){ 
asynQueue.push(callback); 
if(!_execAsyn.isRunning){ 
_execAsyn(); 
} 
}

还是通知Using要加载所需要的模块了,只不过里面加入了一个asynQueue数组和_execAsyn函数,他们的作用分别是

asynQueue是用来保存异步加载之后要回调的函数,没什么好解释的,是一个数组,可以理解为创建了一个函数的队列

_execAsyn是用来执行保存的那些回调函数的,即将所保存的函数逐一执行。看一下代码,代码中对每行的作用都进行了注释

var _execAsyn = function(){ 
// 创建一个变量来缓存需要执行的函数 
var func = null; 
// 如果队列中还有未执行的函数 则进行执行操作 
if(asynQueue.length > 0){ 
// 将_execAsyn函数修改为运行状态 
_execAsyn.isRunning = true; 
// 得到队列中第一个需要执行的函数 
func = asynQueue.shift(); 
// 调用异步加载模块Using.fn.script函数 并传入加载完毕之后需要执行的回调函数 
Using.fn.script(function(){ 
// 当前需要执行的函数 
func(); 
// 迭代_execAsyn 直到队列中没有需要执行的函数 
_execAsyn(); 
}); 
// 若队列中没有需要执行的函数 
}else{ 
// 则将_execAsyn运行状态改为false 
_execAsyn.isRunning = false; 
} 
}

这个函数,解释起来没什么特别的,说白了就是一个一个的执行需要执行的函数。那么,唯一需要注意的就是为什么操作队列的时候没有采用循环,而是使用迭代。那原因就是

1、队列中随时可能有新的函数需要执行,采用循环的话,可能执行不到最新的函数,因为函数总是插入到队列的尾部

2、 Using.fn.script是异步的,如果是循环的话,当前函数还没有执行完,可能下一个函数就已经进入了执行状态。那么,本身来说,同时执行几个函数,速率上可能会更高,为什么这里还要限制其多个函数并行呢?原因也很简单,因为每一次执行队列中的函数,可能都需要加载相应的模块,那么如果刚好友两个或者多个依赖相同模块的函数需要执行,而且并行执行,就可能出现同一个模块加载多次,并可能造成后续的函数执行不了,出现异常。

整个UsingJS的核心部分就这些。在其中我加入了Using.Class.create函数,这个函数在javascript动态加载文章的末尾有提到。

最后看一下页面使用情况:

<script type="text/javascript" src="js/using-0.4.2.min.js"></script> 
<script type="text/javascript"> 
Using("jq"); 
Using("UserView"); 
Using("jq"); Using.ready(function(){ 
Using.asyn(function(){ 
$("#panel").click(function(){ 
alert("by jquery"); 
}); 
}); 
}); 
Using.ready(function(){ 
Using("Http"); 
Using.asyn(function(){ 
var http = new Using.Modules.Http(); 
http.set("xxx"); 
http.show(); 
}); 
Using.asyn(function(){ 
var h = new Using.Modules.Http(); 
h.set("ooo"); 
h.show(); 
}); 
Using("jq"); 
Using.asyn(function(){ 
$("#panel").click(function(){ 
alert("loaded jquery"); 
}); 
}); 
}); 
</script>

这个一段代码,刻意进行重复加载,多次Ready事件和Ready之后进行Using导包。

有一个特别需要注意的地方

Using("Http"); 
Using.asyn(function(){ 
var http = new Using.Modules.Http(); 
http.set("xxx"); 
http.show(); 
}); 
// 假如在这个地方使用 
// var ht = new Using.Modules.Http(); 
// 是会报Using.Modules.Http不是一个constructor 
// 原因就是 
// 任何操作都是异步的,当执行此句时Using("Http")这个模块载入可能还没有完成 
// 这一点是仲谋给多个朋友进行使用时会犯的错误 总以为导包之后 万事大吉 
// 是的 本身应该是这样 导包之后 在任何地方都可以随意引用 
// 但是总得有个前提吧 那就是模块得加载完毕 
// 所以 还请将所有的代码都写在Using.asyn之内 
Using.asyn(function(){ 
var h = new Using.Modules.Http(); 
h.set("ooo"); 
h.show(); 
});

UsingJS下载
Javascript 相关文章推荐
jquery中获取元素里某一特定子元素的代码
Dec 02 Javascript
JavaScript和HTML DOM的区别与联系及Javascript和DOM的关系
Nov 15 Javascript
jQuery插件实现文件上传功能(支持拖拽)
Aug 27 Javascript
BootStrap+Mybatis框架下实现表单提交数据重复验证
Mar 23 Javascript
vue router路由嵌套不显示问题的解决方法
Jun 17 Javascript
使用JS动态显示文本
Sep 09 Javascript
vue项目中v-model父子组件通信的实现详解
Dec 10 Javascript
谈谈React中的Render Props模式
Dec 06 Javascript
DatePickerDialog 自定义样式及使用全解
Jul 09 Javascript
基于jQuery实现挂号平台首页源码
Jan 06 jQuery
JS禁用右键、禁用Ctrl+u、禁用Ctrl+s、禁用F12的实现代码
Dec 01 Javascript
微信小程序实现自定义底部导航
Nov 18 Javascript
javascript动态加载二
Aug 22 #Javascript
javascript动态加载实现方法一
Aug 22 #Javascript
原生js写的放大镜效果
Aug 22 #Javascript
window.open不被拦截的实现代码
Aug 22 #Javascript
EASYUI TREEGRID异步加载数据实现方法
Aug 22 #Javascript
网页打开自动最大化的js代码
Aug 22 #Javascript
精心挑选的12款优秀的基于jQuery的手风琴效果插件和教程
Aug 22 #Javascript
You might like
全国FM电台频率大全 - 24 贵州省
2020/03/11 无线电
PHP的简易冒泡法代码分享
2012/08/28 PHP
php使用fullcalendar日历插件详解
2019/03/06 PHP
checkbox 多选框 联动实现代码
2008/10/22 Javascript
Jquery数独游戏解析(一)-页面布局
2010/11/05 Javascript
JQuery中attr方法和removeAttr方法用法实例
2015/05/18 Javascript
JavaScript SHA1加密算法实现详细代码
2016/10/06 Javascript
JS制作适用于手机和电脑的通知信息效果
2016/10/28 Javascript
jquery uploadify如何取消已上传成功文件
2017/02/08 Javascript
JQuery查找子元素find()和遍历集合each的方法总结
2017/03/07 Javascript
Vue Spa切换页面时更改标题的实例代码
2017/07/15 Javascript
javascript实现QQ空间相册展示源码
2017/12/12 Javascript
jQuery实现新闻播报滚动及淡入淡出效果示例
2018/03/23 jQuery
ztree加载完成后显示勾选节点的实现代码
2018/10/22 Javascript
vue 设置 input 为不可以编辑的实现方法
2019/09/19 Javascript
webpack5 联邦模块介绍详解
2020/07/08 Javascript
详解实现vue的数据响应式原理
2021/01/20 Vue.js
Pycharm学习教程(2) 代码风格
2017/05/02 Python
10分钟教你用Python实现微信自动回复功能
2018/11/28 Python
Python matplotlib生成图片背景透明的示例代码
2019/08/30 Python
python 3.74 运行import numpy as np 报错lib\site-packages\numpy\__init__.py
2019/10/06 Python
django 实现celery动态设置周期任务执行时间
2019/11/19 Python
python学习将数据写入文件并保存方法
2020/06/07 Python
pytorch 计算ConvTranspose1d输出特征大小方式
2020/06/23 Python
Original Penguin美国官网:布拉德皮特、强尼德普喜爱的服装品牌
2016/10/25 全球购物
德国综合购物网站:OTTO
2018/11/13 全球购物
以设计师精品品质提供快速时尚:Mostata
2019/05/10 全球购物
师德个人剖析材料
2014/02/02 职场文书
阳光体育活动实施方案
2014/05/25 职场文书
初中生300字旷课检讨书
2014/11/19 职场文书
2015年图书馆个人工作总结
2015/05/26 职场文书
2015新教师教学工作总结
2015/07/22 职场文书
python 命令行传参方法总结
2021/05/25 Python
Logback 使用TurboFilter实现日志级别等内容的动态修改操作
2021/08/30 Java/Android
MySQL实现配置主从复制项目实践
2022/03/31 MySQL
Python 第三方库 openpyxl 的安装过程
2022/12/24 Python