背景:

  在现在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. UVALive 5099

    B - Nubulsa Expo Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit S ...

  2. Python+Selenium 自动化实现实例-打开浏览器模拟进行搜索数据并验证

    #导入模块 from selenium import webdriverfrom selenium.webdriver.common.keys import Keys #启动火狐浏览器driver = ...

  3. Linked List Cycle I&&II——快慢指针(II还没有完全理解)

    Linked List Cycle I Given a linked list, determine if it has a cycle in it. Follow up: Can you solve ...

  4. System.Web.HttpContext.Current.Request用法

    public static void SetRegisterSource() { if (System.Web.HttpContext.Current.Request["website&qu ...

  5. RedHat7/Centos7 搭建NFS服务器

    https://blog.csdn.net/u012124304/article/details/81001068 客户端和服务器都得安装nfs-utils

  6. python打印所有汉字

    n=0 for ch in xrange(0x4e00, 0x9fa6): print unichr(ch), n = n+1 if(n%50==0): print '\n' print n

  7. CodeForces 143C Help Farmer

    暴力枚举. 枚举最小的那个数字,不会超过$1000$,剩下的两个数字根号的效率枚举一下即可. #include<bits/stdc++.h> using namespace std; lo ...

  8. webpack 打包过程及常用插件

    前言 要理解webpack 首先明白三个概念:module,chunk,bundles,即输入,中间态,输出. chunk: This webpack-specific term is uesd in ...

  9. JSON APIs and Ajax

    1. 通过jQuery来绑定点击事件. 函数 $(document).ready()这个函数中的代码只会在我们的页面加载时候运行一次,确保执行js之前页面所有的dom已经准备就绪. 在$(docume ...

  10. Python中sorted函数的用法(转)

    [Python] sorted函数 我们需要对List.Dict进行排序,Python提供了两个方法 对给定的List L进行排序, 方法1.用List的成员函数sort进行排序,在本地进行排序,不返 ...