Ext源码分析:Ext.onReady到底做了什么?
2010-04-13 23:52
627 查看
2008年4月12日
评论 发表评论
注意:这篇文章我是针对FF来写的,看完这篇文章,你能把IE的也写出来,就说明你入门了:)
代码下面有下载, 无 需引入任何js
首先,我们来看下面的代码片段
Crab = {};
Crab.util = {};//把Namespace模拟出来
Crab.EventManager = function(){//仔细看看这个单例模式,以后调用Crab.EventManager其实得到的就是pub对象
var pub = {
onDocumentReady : function(fn){…};
};
return pub;
}();
Crab.onReady = Crab.EventManager.onDocumentReady;//命名空间的转换
Crab.onReady(function(){
alert(‘hello crabone.com‘);
});
上面是一个大的架子,我们往里面分析进去。Crab.onReady里的方法其实就是被传入onDocumentReady了。
onDocumentReady : function(fn){
if(docReadyState){ // 如果已经调用过Crab.onReady()
docReadyEvent.addListener(fn);
docReadyEvent.fire();
docReadyEvent.clearListeners();
return;
}
if(!docReadyEvent){//如果docReadyEvent还没有创建,我们来初始化
initDocReady();
}
docReadyEvent.addListener(fn);
}
看完上面的注释,再仔细分析后,可以看出docReadyEvent是一个重要的家伙,可以说,onReady里的方法就是这家伙通过fire()来执行的。那么我们来看看,创建这个家伙的initDocReady做了些什么?
var initDocReady = function(){
docReadyEvent = new Crab.util.Event();//原来这家伙是它
document.addEventListener("DOMContentLoaded", fireDocReady, false);//委托document,当页面载入完成的时候,调用fireDocReady
};
看到这里,我们来整理下思路,首先,第一次调用onDocumentReady 的时候 ,做了这么三件事
1、docReadyEvent = new Crab.util.Event();
2、document.addEventListener(”DOMContentLoaded”, fireDocReady, false);
3、docReadyEvent.addListener(fn);
特别是第二件事情,我们要注意,仅仅是委托了而已,并没有执行fireDocReady
OK,做完上面三件事情后,FF又往下面执行下去了,读出所有的DOM后,开始调用fireDocReady了!!
我们来看看fireDocReady干了些什么?
var fireDocReady = function(){
if(!docReadyState){
docReadyState = true;//设置为已经调用了onReady了
document.removeEventListener("DOMContentLoaded", fireDocReady, false);//将先前的委托取消
if(docReadyEvent){
docReadyEvent.fire();//fire了
docReadyEvent.clearListeners();//清空!
}
}
};
可见,最终还是由docReadyEvent这家伙在执行我们的方法。
再回顾下,onDocumentReady 里面,当已经执行过onReady的时候,做了些什么?
docReadyEvent.addListener(fn);
docReadyEvent.fire();
docReadyEvent.clearListeners();
可见,还是它。下面我贴出,docReadyEvent的代码片段,记住,它是docReadyEvent = new Crab.util.Event();代码有点长,耐心看下去
(function(){
Crab.util.Event = function(obj){
this.listeners = [];
};
Crab.util.Event.prototype = {
addListener : function(fn){
if(!this.isListening(fn)){
var l = this.createListener(fn);
if(!this.firing){
this.listeners.push(l);
}else{ // if we are currently firing this event, don’t disturb the listener loop
this.listeners = this.listeners.slice(0);
this.listeners.push(l);
}
}
},
createListener : function(fn){
var l = {
fn:fn,
fireFn:fn
};
return l;
},
findListener : function(fn){
var ls = this.listeners;
for(var i = 0, len = ls.length; i < len; i++){
var l = ls[i];
if(l.fn == fn){
return i;
}
}
return -1;
},
isListening : function(fn){
return this.findListener(fn) != -1;
},
clearListeners : function(){
this.listeners = [];
},
fire : function(){
var ls = this.listeners, len = ls.length;
if(len > 0){
this.firing = true;
var args = Array.prototype.slice.call(arguments, 0);
for(var i = 0; i < len; i++){
var l = ls[i];
if(l.fireFn.apply(window, arguments) === false){
this.firing = false;
return false;
}
}
this.firing = false;
}
return true;
}
};
})();
上面的代码我已经简单化了,看起来应该不会太累,当然如果您觉得吃不消了,应该去补补javascript的基础了。回到正题,Event其实是一个方法容器,并不应该翻译成监听器容器,因为在这里它根本就没有去监听事件,而是保存很多方法而已,那么fire()的功能就是去循环这个容器,将里面的方法一一执行。这里就引出一个问题了,我们传进去的方法是如何被执行的?要知道
Ext.onReady(function(){});
里面的可是匿名方法啊,不能通过 方法名() 这样的方法来执行,那么怎么办?
通过方法委托来执行! l.fireFn.apply(window, arguments) 将fireFn委托给window执行,看到这里别迷惑,要知道,我们写如下方法
function aa(){}
aa();
其实aa();就应该等于window.aa();大家应该记得window.alert()=alert()吧?呵呵
如果还不懂就发邮件或者留言问我吧~~~
代码下载(记住,这个程序只支持FF哦)
评论 发表评论
注意:这篇文章我是针对FF来写的,看完这篇文章,你能把IE的也写出来,就说明你入门了:)
代码下面有下载, 无 需引入任何js
首先,我们来看下面的代码片段
Crab = {};
Crab.util = {};//把Namespace模拟出来
Crab.EventManager = function(){//仔细看看这个单例模式,以后调用Crab.EventManager其实得到的就是pub对象
var pub = {
onDocumentReady : function(fn){…};
};
return pub;
}();
Crab.onReady = Crab.EventManager.onDocumentReady;//命名空间的转换
Crab.onReady(function(){
alert(‘hello crabone.com‘);
});
上面是一个大的架子,我们往里面分析进去。Crab.onReady里的方法其实就是被传入onDocumentReady了。
onDocumentReady : function(fn){
if(docReadyState){ // 如果已经调用过Crab.onReady()
docReadyEvent.addListener(fn);
docReadyEvent.fire();
docReadyEvent.clearListeners();
return;
}
if(!docReadyEvent){//如果docReadyEvent还没有创建,我们来初始化
initDocReady();
}
docReadyEvent.addListener(fn);
}
看完上面的注释,再仔细分析后,可以看出docReadyEvent是一个重要的家伙,可以说,onReady里的方法就是这家伙通过fire()来执行的。那么我们来看看,创建这个家伙的initDocReady做了些什么?
var initDocReady = function(){
docReadyEvent = new Crab.util.Event();//原来这家伙是它
document.addEventListener("DOMContentLoaded", fireDocReady, false);//委托document,当页面载入完成的时候,调用fireDocReady
};
看到这里,我们来整理下思路,首先,第一次调用onDocumentReady 的时候 ,做了这么三件事
1、docReadyEvent = new Crab.util.Event();
2、document.addEventListener(”DOMContentLoaded”, fireDocReady, false);
3、docReadyEvent.addListener(fn);
特别是第二件事情,我们要注意,仅仅是委托了而已,并没有执行fireDocReady
OK,做完上面三件事情后,FF又往下面执行下去了,读出所有的DOM后,开始调用fireDocReady了!!
我们来看看fireDocReady干了些什么?
var fireDocReady = function(){
if(!docReadyState){
docReadyState = true;//设置为已经调用了onReady了
document.removeEventListener("DOMContentLoaded", fireDocReady, false);//将先前的委托取消
if(docReadyEvent){
docReadyEvent.fire();//fire了
docReadyEvent.clearListeners();//清空!
}
}
};
可见,最终还是由docReadyEvent这家伙在执行我们的方法。
再回顾下,onDocumentReady 里面,当已经执行过onReady的时候,做了些什么?
docReadyEvent.addListener(fn);
docReadyEvent.fire();
docReadyEvent.clearListeners();
可见,还是它。下面我贴出,docReadyEvent的代码片段,记住,它是docReadyEvent = new Crab.util.Event();代码有点长,耐心看下去
(function(){
Crab.util.Event = function(obj){
this.listeners = [];
};
Crab.util.Event.prototype = {
addListener : function(fn){
if(!this.isListening(fn)){
var l = this.createListener(fn);
if(!this.firing){
this.listeners.push(l);
}else{ // if we are currently firing this event, don’t disturb the listener loop
this.listeners = this.listeners.slice(0);
this.listeners.push(l);
}
}
},
createListener : function(fn){
var l = {
fn:fn,
fireFn:fn
};
return l;
},
findListener : function(fn){
var ls = this.listeners;
for(var i = 0, len = ls.length; i < len; i++){
var l = ls[i];
if(l.fn == fn){
return i;
}
}
return -1;
},
isListening : function(fn){
return this.findListener(fn) != -1;
},
clearListeners : function(){
this.listeners = [];
},
fire : function(){
var ls = this.listeners, len = ls.length;
if(len > 0){
this.firing = true;
var args = Array.prototype.slice.call(arguments, 0);
for(var i = 0; i < len; i++){
var l = ls[i];
if(l.fireFn.apply(window, arguments) === false){
this.firing = false;
return false;
}
}
this.firing = false;
}
return true;
}
};
})();
上面的代码我已经简单化了,看起来应该不会太累,当然如果您觉得吃不消了,应该去补补javascript的基础了。回到正题,Event其实是一个方法容器,并不应该翻译成监听器容器,因为在这里它根本就没有去监听事件,而是保存很多方法而已,那么fire()的功能就是去循环这个容器,将里面的方法一一执行。这里就引出一个问题了,我们传进去的方法是如何被执行的?要知道
Ext.onReady(function(){});
里面的可是匿名方法啊,不能通过 方法名() 这样的方法来执行,那么怎么办?
通过方法委托来执行! l.fireFn.apply(window, arguments) 将fireFn委托给window执行,看到这里别迷惑,要知道,我们写如下方法
function aa(){}
aa();
其实aa();就应该等于window.aa();大家应该记得window.alert()=alert()吧?呵呵
如果还不懂就发邮件或者留言问我吧~~~
代码下载(记住,这个程序只支持FF哦)
相关文章推荐
- Ext源码分析:Ext.onReady到底做了什么?
- Ext源码分析:Ext.onReady到底做了什么?
- Ext源码分析:Ext.onReady到底做了什么
- 从vue.js的源码分析,input和textarea上的v-model指令到底做了什么
- 源码级分析测试彻底搞懂String.trim()到底干了什么[base jdk8]
- 从vue.js的源码分析,input和textarea上的v-model指令到底做了什么
- HDFS源码分析:“-put”到底做了些什么(客户端)
- 分析源码到底是为了什么
- 分析zookeeper到底能做什么?
- 一)我要做什么,Petshop 源码分析
- 每天一点点-EXT源码分析之二
- 每天一点点-EXT源码分析六
- Ext源码分析:解析Ext的命名空间,Ext.namespace
- 每天一点点-ext源码分析之七
- Android的Message Pool是个什么鬼——源码角度分析
- Ext源码分析之模板模式解说——Ext组件渲染render的全过程详述
- 每天一点点-EXT源码分析之五
- 需求分析到底说的是什么?
- UDT源码分析(1):UDT协议是什么?
- 谷歌Analytics(分析)跳出率 - 到底什么意思