背景:

  在现在WEB开发中,稍复杂一点的页面,都会涉及到多个模块,尤其是类似seajs、LABjs、requireJS等模块工具出来后,前端开发者分模块开发已经慢慢变成一种习惯了,但是多个模块间的常常有各种交集,需要通信、需要互相调用,这时监听者模式便是必不可少的一种设计模式了,在前端表现事件操作。backbone和jquery都有提供了很好的事件处理方式。

  但是,真正开发需求的时候我们常常会遇到文件加载顺序跟事件监听与更新不一致的需求,比如说:在一个视频网站里面,有一个视频处理的JS模块和用户信息处理模块,现在需要先加载视频模块的JS使得能第一时间把视频展示给用户看,但是在展示完视频的同时需要视频JS模块会更新一个在用户信息处理模块里面监听的发送用户查看视频记录的模块,这时候由于用户信息处理模块未加载,所以会导致事件未定义且不被执行,这时我们希望的是就算是之前更新的,用户信息处理模块在初始化监听时能知道之前已经被更新过了,并执行该更新。下面就是来实现不依赖JS加载顺序事件对象的实现吧:

基础:

(function(){
var obListenList = {}; //监听者事件列表
var OB = {
listen : function(listenStr,func){
if(!obListenList[listenStr]){
obListenList[listenStr] = [];
}
obListenList[listenStr].push(func);
},
update : function(listenStr,datas){
if(typeof obListenList[listenStr] != "undefined"){
var len = obListenList[listenStr].length,
i = 0;
for( ; i < len ; i++){
if(typeof(obListenList[listenStr][i])=="function"){
obListenList[listenStr][i](datas);
}
}
}
}
};
window.OB = OB;
}()); OB.listen("say",function(msg){
document.write(msg + "<br/>");
});
OB.update("say","She say : Im your's!");

  基础的事件编写很简单,只需要用一个对象把被监听的事件的函数列表放在一个对象(obListenList)里面,在update的时候查看遍历调用就是了。

实现先更新,等监听的时候也会执行之前的更新:

(function(){
var obListenList = {}, //监听事件列表
obUpdateList = {} , // 更新事件列表
obUpdateListLen = 2 , //最大监听更新队列数
obUpdateWaitFlag = true ; var OB = {
listen : function(listenStr,func){
if(!obListenList[listenStr]){
obListenList[listenStr] = [];
}
obListenList[listenStr].push(func); //查看之前是否有更新过
if(typeof obUpdateList[listenStr] != "undefined"){
var lStrArg = obUpdateList[listenStr];
for(var i = 0 ; i < lStrArg.length; i ++ ){
func(lStrArg[i]);
}
} },
update : function(listenStr,datas){ if(typeof obListenList[listenStr] != "undefined"){
var len = obListenList[listenStr].length,
i = 0;
for( ; i < len ; i++){
if(typeof(obListenList[listenStr][i])=="function"){
obListenList[listenStr][i](datas);
}
}
}
if(obUpdateWaitFlag){ //往该事件更新队列里面添加数据
if(typeof obUpdateList[listenStr] == "undefined"){
obUpdateList[listenStr] = [];
}
obUpdateList[listenStr].push(datas); //如果超过允许的最大长度就不要再往里面添加了,防止内在溢出
if(obUpdateList[listenStr].length>=obUpdateListLen){
obUpdateWaitFlag = false;
}
}
}
};
window.OB = OB;
}()); OB.update("say","She say : Im your's!--1");
OB.update("say","She say : Im your's!--2");
OB.update("say","She say : Im your's!--3");
OB.listen("say",function(msg){
document.write(msg + "<br/>");
});
OB.update("say","She say : Im your's!--4"); /* 结果是:
* She say : Im your's!--1
* She say : Im your's!--2
* She say : Im your's!--4
*/

  看下代码,实现起来也不是很难有三个关键点:

    1,在更新事件的时候将事件传入的参数传进更新事件列表里面

    2,在监听事件初始化后,查看更新事件列表里面有没有对应事件需要更新的数据,如果有,便遍历执行一遍

    3,一定要给更新事件列表设定一个最大保留监听的事件长度(obUpdateListLen),因为在一些复杂的页面程序中可能会有某个无限的更新,如果不做限制必然导致内存溢出。

优化:

(function() {

    if(typeof OB !== "undefined"){//防止文件重复加载导致事件队列被清空
return ;
} var obListenList = {} , //存储监听队列
obUpdateList = {} , //存储更新队列
obUpdateListLen = 2 , //存储更新队列最多保存长度
obUpdateWaitFlag = true ; //记录是否达到了存储更新队列的最大值 var OB = function (listenStr){
return new OB.prototype.init(listenStr);
}; OB.prototype = {
listenStr : "",
instance : null,
init : function(listenStr){
if(OB.prototype.instance){
OB.prototype.instance.setListenStr(listenStr);
return OB.prototype.instance;
} this.setListenStr(listenStr); OB.prototype.instance = this;
return this;
},
setListenStr : function(listenStr){
this.listenStr = listenStr;
},
listen : function(func){
if(this.listenStr){
if(!obListenList[this.listenStr]){
obListenList[this.listenStr] = [];
}
obListenList[this.listenStr].push(func); //查看之前是否有更新过
if(typeof obUpdateList[this.listenStr] != "undefined"){
var lStrArg = obUpdateList[this.listenStr];
for(var i = 0 ; i < lStrArg.length; i ++ ){
func.apply(this,lStrArg[i]);
}
}
}
},
update : function(){
if(typeof obListenList[this.listenStr] != "undefined"){
var len = obListenList[this.listenStr].length,
i = 0;
for( ; i < len ; i++){
if(typeof(obListenList[this.listenStr][i])=="function"){
obListenList[this.listenStr][i].apply(this,arguments);
}
}
}
if(obUpdateWaitFlag){
if(typeof obUpdateList[this.listenStr] == "undefined"){
obUpdateList[this.listenStr] = [];
}
obUpdateList[this.listenStr].push(arguments); if(obUpdateList[this.listenStr].length>=obUpdateListLen){
obUpdateWaitFlag = false;
}
}
}
}; OB.prototype.init.prototype = OB.prototype;
window.OB = OB; //兼容seaJS和requireJS
if ( typeof define === "function" && ( define.cmd || define.amd ) ) {
define( "observer", [], function() {
return OB;
});
} }()); OB("say").update("She say : Im your's!--1");
OB("say").update("She say : Im your's!--2");
OB("say").update("She say : Im your's!--3");
OB("say").listen(function(msg){
document.write(msg + "<br/>");
});
OB("say").update("He Say : yes! you are mine!"); /* 结果是:
* She say : Im your's!--1
* She say : Im your's!--2
* He Say : yes! you are mine!
*/

  这里主要是几个点的优化:

  1,操作优化,使用了JQuery原型模式实现了JQuery操作方式,具体的原理可以参考《犀利开发:jQuery内核详解与实践》 这本书

  2,支持AMD和CMD模块,方便直接应用到SeaJS或requireJS等项目

  3,防止重复加载导致事件列表被清空

这个只是本人的实践经历,写法可能没有那么优美,但是基本功能已经出来了,希望对大家的项目有所帮助,如果有存在什么问题,也可以回复一下。

javascript不依赖JS加载顺序事件对象实现的更多相关文章

  1. (转)JS加载顺序

    原文:http://blog.csdn.net/dannywj1371/article/details/7048076 JS加载顺序 做一名合格的前端开发工程师(12篇)——第一篇 Javascrip ...

  2. 组件推荐Forloop.HtmlHelpers 用来实现MVC的js加载顺序

    最近在开发的时候遇到js加载顺序的问题,layui在底部声明了js,但是我想在页面其他地方使用分布视图,分布视图内有自己的js逻辑,发现不能执行,一看就发现,这里的js应该加在layui后面执行才能有 ...

  3. cookie.js 加载顺序问题

    今天遇到一个问题,在使用cookie.js时,只有在jquery.js文件后加载整体才有效 有效加载顺序 <head> <script type="text/javascr ...

  4. 记录一个bootstrap因js加载顺序导致的问题(tstrap-table-mobile.min.js:7 Uncaught TypeError: Cannot read property 'defaults' of undefined)

    问题描述: 网上找了会没看到答案,然后看了下源码,发现也没有问题,想到js加载的顺序,改了下,发现问题没了. 正确的顺序: 我之前把 <script src="/js/plugins/ ...

  5. 小程序页面的四种文件(JSON、WXML、WXSS、JS)加载顺序

    一个小程序页面由四种文件组成: 1)json 页面配置文件 2)js 页面逻辑文件(必需) 3)wxml 页面结构文件(必需) 4)wxss 页面样式文件 这四个文件的加载顺序: 第一步: 加载页面j ...

  6. html,css,js加载顺序

    1.js放在head中会立即执行,阻塞后续的资源下载与执行.因为js有可能会修改dom,如果不阻塞后续的资源下载,dom的操作顺序不可控. 正常的网页加载流程是这样的. 浏览器一边下载HTML网页,一 ...

  7. js加载顺序

    在jsp页面中引js文件,页面按照js顺序加载,若js中存在相同的方法,应该会执行顺序在前的js中的方法.有时候遇到js方法不执行或者执行不对的情况,可能就是js的顺序问题,有时候会找很久找不到问题. ...

  8. 【Spring】依赖注入 加载顺序

    一.Spring依赖注入depents-on参数 depents-on是指指定Bean初始化及销毁时的顺序,使用depends-on属性指定的是Bean要先初始化完毕后才初始化当前Bean,由于只有S ...

  9. JS 页面加载触发事件 document.ready和window.onload的区别

    document.ready和onload的区别——JavaScript文档加载完成事件页面加载完成有两种事件: 一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件): 二是onlo ...

随机推荐

  1. 16:django 有条件的视图处理(Last-Modified和ETag)&&加密签名

    有条件的视图处理 上一节我们介绍了缓存来减轻服务器的负担,这里的有条件的视图处理也从一定程度上减轻了服务器的负担,在正式介绍之前,先来看两个概念:Last-Modified和ETag Last-Mod ...

  2. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记3——输入消息处理,物理建模与粒子系统初步

    第7章 Windows游戏输入消息处理 1. 键盘消息处理 之前提到的窗口过程函数有两参数与消息输出有关——wParam和llParam LRESULT CALLBACK WindowProc( _I ...

  3. javascript定义对象的方式

    javascript定义对象的方式(javascript中没有类,只有对象)1)基于已有对象扩充属性和方法(弊端:每次创建都与要重新定义属性方法) var object = new Object(); ...

  4. jquery&javascript 跨域jsonp

    $(function(){ $.ajax({ type: "get", async: false, url: "http://flightQuery.com/jsonp/ ...

  5. jQuery文档处理

    1.wrap 把所有匹配的元素用其他元素的结构化标记包裹起来.(我的理解就是给匹配的元素穿一件衣服) 把所有的段落用一个新创建的div包裹起来 $("p").wrap(" ...

  6. python 简单日志框架 自定义logger

    转载请注明: 仰望高端玩家的小清新 http://www.cnblogs.com/luruiyuan/ 通常我们在构建 python 系统时,往往需要一个简单的 logging 框架.python 自 ...

  7. 【Java多线程】线程池学习

    Java线程池学习 众所周知,Java不仅提供了线程,也提供了线程池库给我们使用,那么今天来学学线程池的具体使用以及线程池基本实现原理分析. ThreadPoolExecutor ThreadPool ...

  8. 50 years, 50 colors HDU - 1498(最小点覆盖或者说最小顶点匹配)

    On Octorber 21st, HDU 50-year-celebration, 50-color balloons floating around the campus, it's so nic ...

  9. 【BZOJ 3993】【SDOI 2015】序列统计

    http://www.lydsy.com/JudgeOnline/problem.php?id=3992 这道题好难啊. 第一眼谁都能看出来是个dp,设\(f(i,j)\)表示转移到第i位时前i位的乘 ...

  10. [BZOJ1913][APIO2010]信号覆盖(计算几何+计数)

    1913: [Apio2010]signaling 信号覆盖 Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1658  Solved: 672[Subm ...