代碼如下: 1:Namespace('logtest') => new NamespaceDefinition(NamespaceObjectFactory.create('logtest')) 代碼如下: 代碼如下: ps:具體內(nèi)部調(diào)用關(guān)系還是沒有弄明白,今后有時間再整理,這篇太亂了。
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com
1 var Namespace = (function(){
2 /* utility */
3 var merge = function(target, source){ // 把source的所有自身屬性copy到target中去,并返回target對象 4 for(var p in source)
5 if(source.hasOwnProperty( p )) target[p] = source[p];
6 return target;
7 };
8 var _assertValidFQN = function(fqn){ // 驗證namespace名字的有效性,必須是小寫英數(shù)字,下劃線和點
9 if(!(/^[a-z0-9_.]+/).test(fqn)) throw('invalid namespace');
10 };
11
12 var Procedure = function _Private_Class_Of_Proc(){
13 merge(this, {
14 state : {}, // 狀態(tài)
15 steps : [], // 存儲狀態(tài)的數(shù)組
16 _status: 'init'
17 });
18 };
19 merge(Procedure.prototype, {
20 next: function(state){ // 如果state有值,存入到steps隊列隊尾,然后返回this
21 if(state) this.enqueue(state);
22 return this;
23 },
24 isRunning: function(){ // 判定是否為running狀態(tài)
25 return (this._status === 'running');
26 },
27 enqueue: function(state){ // 這里其實是用數(shù)組steps來模擬隊列,enqueue就是從隊尾入隊列
28 this.steps.push(state);
29 },
30 dequeue: function(){ // dequeue就是從對頭出隊列
31 return this.steps.shift();
32 },
33 call: function(initialState,callback){ //
34 if( this.isRunning() ) throw("do not run twice");
35
36 this.state = initialState || {}; // 保存當(dāng)前state(NamespaceDefinition對象)
37 this.enqueue(function($c){ // 函數(shù)入隊列steps
38 $c(); // 執(zhí)行傳進來的函數(shù)
39 if(callback)callback(this); // 如果存在回調(diào)函數(shù)的,執(zhí)行回調(diào)函數(shù)
40 });
41 this._status = 'running'; // 設(shè)置狀態(tài)為running
42 this._invoke(); // 調(diào)用_invoke
43 },
44 _invoke: function(){
45 var _self = this;
46 var step = _self.dequeue(); // 對象出隊列(FIFO)
47 if( !step ){
48 _self._status = 'finished'; // 如果隊列為空,則設(shè)置狀態(tài)為finished
49 return;
50 } // step是數(shù)組的情況下不走這條路徑
51 if( step.call ) { // 如果該對象是函數(shù)對象的時候,則執(zhí)行該call方法,并指定內(nèi)部this為_self.state,回調(diào)函數(shù)里面繼續(xù)調(diào)用_invoke
52 return step.call( _self.state,function _cont(state){
53 if( state ) _self.state = state;
54 _self._invoke();
55 });
56 }
57 var finishedProcess = 0;
58 if( step.length === 0 ) _self._invoke(); // 如果該數(shù)組長度為0,則調(diào)用_invoke
59 for(var i =0,l=step.length;i
61 finishedProcess++;
62 if( finishedProcess == l ){
63 _self._invoke();
64 }
65 });
66 }
67 }
68 });
69
70 var createProcedure = function(state) {
71 return new Procedure().next(state);
72 };
73
74 var NamespaceObject = function _Private_Class_Of_NamespaceObject(fqn){
75 merge(this, {
76 stash: { CURRENT_NAMESPACE : fqn },
77 fqn : fqn,
78 proc : createProcedure()
79 });
80 };
81 merge(NamespaceObject.prototype, {
82 enqueue: function(context) {
83 this.proc.next(context);
84 },
85 call: function(state,callback) {
86 this.proc.call(state, callback);
87 },
88 valueOf: function() {
89 return "#NamespaceObject<" + this.fqn + ">";
90 },
91 merge: function(obj) {
92 merge(this.stash,obj);
93 return this;
94 },
95 getStash: function() {
96 return this.stash;
97 },
98 getExport: function(importName) {
99 if (importName === '*') return this.stash;
100
101 var importNames = importName.split(/,/),
102 retStash = {};
103 for(var i = 0,l=importNames.length;i
105 }
106 return retStash;
107 }
108 });
109 var NamespaceObjectFactory = (function() {
110 var cache = {};
111 return {
112 create :function(fqn){
113 _assertValidFQN(fqn);
114 return (cache[fqn] || (cache[fqn] = new NamespaceObject(fqn)));
115 }
116 };
117 })();
118
119 var NamespaceDefinition = function _Private_Class_Of_NamespaceDefinition(nsObj) {
120 merge(this, {
121 namespaceObject: nsObj,
122 requires : [],
123 useList : [],
124 stash : {},
125 defineCallback : undefined
126 });
127 var _self = this;
128 nsObj.enqueue(function($c){ _self.apply($c); });
129 };
130 merge(NamespaceDefinition.prototype, {
131 use: function(syntax){ // 使用namespace
132 this.useList.push(syntax); // 該namespace字符串存入數(shù)組useList
133 var splitted = syntax.split(/\s+/); // namespace和它的對象使用空格分開
134 var fqn = splitted[0]; // 取得namespace
135 var importName = splitted[1]; // 取得namespace中的對象
136 _assertValidFQN(fqn);
137 this.requires.push(function($c){ // 放一個函數(shù)到requires數(shù)組中
138 var context = this;
139 var require = NamespaceObjectFactory.create(fqn); // 獲取指定的NamespaceObject對象,之前生成過得對象可以直接從緩存中獲取
140 require.call(this,function(state){ // 調(diào)用NamespaceObject對象的call方法
141 context.loadImport(require,importName);
142 $c();
143 });
144 });
145 return this;
146 },
147 _mergeStashWithNS: function(nsObj){
148 var nsList = nsObj.fqn.split(/\./);
149 var current = this.getStash();
150
151 for(var i = 0,l=nsList.length;i
153 current = current[nsList[i]];
154 }
155
156 var lastLeaf = nsList[nsList.length-1];
157 current[lastLeaf] = merge(current[lastLeaf] || {}, nsObj.getStash());
158 },
159 loadImport: function(nsObj,importName){
160 if( importName ){
161 merge( this.stash, nsObj.getExport(importName) );
162 }else{
163 this._mergeStashWithNS( nsObj );
164 }
165 },
166 define: function(callback){
167 var nsDef = this, nsObj = this.namespaceObject;
168 this.defineCallback = function($c) { // 給defineCallback賦值,同時定義一下該回調(diào)函數(shù)的上下文,nsDef和nsObj兩個對象。
169 var ns = {
170 provide : function(obj){
171 nsObj.merge(obj);
172 $c();
173 }
174 };
175 merge(ns, nsDef.getStash());
176 merge(ns, nsObj.getStash());
177 callback(ns);
178 };
179 },
180 getStash: function(){
181 return this.stash;
182 },
183 valueOf: function(){
184 return "#NamespaceDefinition<"+this.namespaceObject+"> uses :" + this.useList.join(',');
185 },
186 apply: function(callback){
187 var nsDef = this;
188 createProcedure(nsDef.requires)
189 .next(nsDef.defineCallback)
190 .call(nsDef,function(){
191 callback( nsDef.getStash() );
192 });
193 }
194 });
195
196 var createNamespace = function(fqn){
197 return new NamespaceDefinition(
198 NamespaceObjectFactory.create(fqn || 'main')
199 );
200 };
201 merge(createNamespace, {
202 'Object' : NamespaceObjectFactory,
203 Definition: NamespaceDefinition,
204 Proc : createProcedure
205 });
206 return createNamespace;
207 })();
追加定義Namespace支持的方法:
Namespace.use
Namespace.fromInternal
Namespace.GET
Namespace.fromExternal
代碼如下:
1 Namespace.use = function(useSyntax){ return Namespace().use(useSyntax); }
2 Namespace.fromInternal = Namespace.GET = (function(){
3 var get = (function(){
4 var createRequester = function() {
5 var xhr;
6 try { xhr = new XMLHttpRequest() } catch(e) {
7 try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {
8 try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {
9 try { xhr = new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {
10 try { xhr = new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {
11 throw new Error( "This browser does not support XMLHttpRequest." )
12 }
13 }
14 }
15 }
16 }
17 return xhr;
18 };
19 var isSuccessStatus = function(status) {
20 return (status >= 200 && status < 300) ||
21 status == 304 ||
22 status == 1223 ||
23 (!status && (location.protocol == "file:" || location.protocol == "chrome:") );
24 };
25
26 return function(url,callback){
27 var xhr = createRequester();
28 xhr.open('GET',url,true);
29 xhr.onreadystatechange = function(){
30 if(xhr.readyState === 4){
31 if( isSuccessStatus( xhr.status || 0 )){
32 callback(true,xhr.responseText);
33 }else{
34 callback(false);
35 }
36 }
37 };
38 xhr.send('')
39 };
40 })();
41
42 return function(url,isManualProvide){
43 return function(ns){
44 get(url,function(isSuccess,responseText){
45 if( isSuccess ){
46 if( isManualProvide )
47 return eval(responseText);
48 else
49 return ns.provide( eval( responseText ) );
50 }else{
51 var pub = {};
52 pub[url] = 'loading error';
53 ns.provide(pub);
54 }
55 });
56 };
57 };
58 })();
59
60 Namespace.fromExternal = (function(){
61 var callbacks = {};
62 var createScriptElement = function(url,callback){
63 var scriptElement = document.createElement('script');
64
65 scriptElement.loaded = false;
66
67 scriptElement.onload = function(){
68 this.loaded = true;
69 callback();
70 };
71 scriptElement.onreadystatechange = function(){
72 if( !/^(loaded|complete)$/.test( this.readyState )) return;
73 if( this.loaded ) return;
74 scriptElement.loaded = true;
75 callback();
76 };
77 scriptElement.src = url;
78 document.body.appendChild( scriptElement );
79 return scriptElement.src;
80 };
81 var domSrc = function(url){
82 return function(ns){
83 var src = createScriptElement(url,function(){
84 var name = ns.CURRENT_NAMESPACE;
85 var cb = callbacks[name];
86 delete callbacks[name];
87 cb( ns );
88 });
89 }
90 };
91 domSrc.registerCallback = function(namespace,callback) {
92 callbacks[namespace] = callback;
93 };
94 return domSrc;
95 })();
96
97 try{ module.exports = Namespace; }catch(e){}
具體看一個例子:
代碼如下:
1 Namespace('logtest')
2 .define(function (ns) {
3 console.log(2);
4 ns.provide({
5 log : function () { console.log(3); }
6 });
7 });
8
9 console.log(4);
10
11 Namespace
12 .use('logtest')
13 .apply( function (ns) {
14 console.log(5);
15 ns.logtest.log();
16 });
即生成一個NamespaceDefinition對象,該對象是由NamespaceObject對象來初始化的,該對象同時還有三個屬性,Object,Definition,Proc。其值依次為 NamespaceObjectFactory,NamespaceDefinition,createProcedure函數(shù)對象類。Namespace('logtest') 返回的結(jié)果就是生成的NamespaceDefinition對象,然后調(diào)用其define方法,初始化defineCallback。此時僅僅是定義,不做具體的動作。
166 define: function(callback){
167 var nsDef = this, nsObj = this.namespaceObject;
168 this.defineCallback = function($c) { // 給defineCallback賦值,同時定義一下該回調(diào)函數(shù)的上下文,nsDef和nsObj兩個對象。
169 var ns = {
170 provide : function(obj){
171 nsObj.merge(obj);
172 $c();
173 }
174 };
175 merge(ns, nsDef.getStash());
176 merge(ns, nsObj.getStash());
177 callback(ns);
178 };
179 },
2:使用之前定義的namespace里面的對象,Namespace.use() => Namespace().use() => Namespace('main').use()。調(diào)用use的時候初始化requires數(shù)組。
131 use: function(syntax){ // 使用namespace
132 this.useList.push(syntax); // 該namespace字符串存入數(shù)組useList
133 var splitted = syntax.split(/\s+/); // namespace和它的對象使用空格分開
134 var fqn = splitted[0]; // 取得namespace
135 var importName = splitted[1]; // 取得namespace中的對象
136 _assertValidFQN(fqn);
137 this.requires.push(function($c){ // 放一個函數(shù)到requires數(shù)組中
138 var context = this;
139 var require = NamespaceObjectFactory.create(fqn); // 獲取指定的NamespaceObject對象,之前生成過得對象可以直接從緩存中獲取
140 require.call(this,function(state){ // 調(diào)用NamespaceObject對象的call方法
141 context.loadImport(require,importName);
142 $c();
143 });
144 });
145 return this;
146 },
3:調(diào)用main的apply方法。看一下具體的apply方法
代碼如下:
186 apply: function(callback){
187 var nsDef = this;
188 createProcedure(nsDef.requires)
189 .next(nsDef.defineCallback)
190 .call(nsDef,function(){
191 callback( nsDef.getStash() );
192 });
193 }
取出requires數(shù)組里面的對象生成Proc對象,并把該requires數(shù)組里的對象入隊列steps中,還有nsDef.defineCallback也入隊列(此例中為undefined),調(diào)用Proc的call方法。第一個參數(shù)是nsDef,第二個參數(shù)是回調(diào)函數(shù)。
具體使用方法:
在定義Namespace的時候,所有的定義放在define里面,并且以匿名函數(shù)的形式定義。function (ns) { // 具體的實現(xiàn) // 定義對外公開的對象,外部在use該nsName之后,就可以通過ns.nsName.key()來調(diào)用它 ns.provide({ key : value});}
使用namespace.js的好處,所有的定義都是在需要的時候才開始執(zhí)行的,也就是在具體使用的時候才開始解析定義。