背景:

  在现在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. Elasticsearch( 插件开发)

    elasticsearch5.2.2 插件开发(一) Scripting plugins:这个插件本质来说,就是会调用用户的脚本,所以可以执行任何的程序,举例的话,可以通过这个插件,支持javascr ...

  2. 稍微谈一下 javascript 开发中的 MVC 模式

    随着前台开发日益受到重视,客户端代码比重日益增加的今天,如何在javascript开发里应用MVC模式,这个问题似乎会一直被提到,所以偶在这里粗略的谈一下自己的看法吧. MVC模式的基本理念,是通过把 ...

  3. java程序中如何为一个while(true)循环计时,超过一定时间比如10个小时就退出循环?

    public void execute(int hour){ long t1 = System.currentTimeMillis(); while(true){ long t2 = System.c ...

  4. vue-cli中引入jquery方法

    这里有个详解,当然,仅仅是安装jq的话下面这个办法就够了.传送门 在webpack.base.conf.js里加入 var webpack = require("webpack") ...

  5. vue不用webpake等环境及脚手架也可以玩

    初学时,搭环境,es6也来了,vuecil脚手架也弄了,调错,照着教程一遍一遍kei着... 然尔,实际开发中,所写的东西最后是要打包封装成软件的,为了方便其他人修改查看,不能打包成js文件... 难 ...

  6. codeforces 360 B

    B - Levko and Array 题目大意:给你你个长度为n的数列a,你最多改变k个值,max{ abs ( a[ i + 1] - a[ i ] ) } 的最小值为多少. 思路:这个题很难想到 ...

  7. 如何求先序排列和后序排列——hihocoder1049+洛谷1030+HDU1710+POJ2255+UVA548【二叉树递归搜索】

    [已知先序.中序求后序排列]--字符串类型 #1049 : 后序遍历 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho在这一周遇到的问题便是:给出一棵二叉树的前序和 ...

  8. [BZOJ1563][NOI2009]诗人小G(决策单调性优化DP)

    模板题. 每个决策点都有一个作用区间,后来的决策点可能会比先前的优.于是对于每个决策点二分到它会比谁在什么时候更优,得到新的决策点集合与区间. #include<cstdio> #incl ...

  9. 洛谷 P3943 星空

    题目背景 命运偷走如果只留下结果, 时间偷走初衷只留下了苦衷. 你来过,然后你走后,只留下星空. 题目描述 逃不掉的那一天还是来了,小 F 看着夜空发呆. 天上空荡荡的,没有一颗星星——大概是因为天上 ...

  10. bzoj 2137: submultiple

                                                     Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 23 ...