7 (phonegap源碼分析) 平臺相關模塊和初始化(platform)

       之前分析了與平臺無關的common模塊,這節來分析下與平臺相關的platform模塊和phonegap的初始化。

define("myphonegap/platform", function(require, exports, module) {
        module.exports = {
			id: "android",
			initialize:function() {
				 
			}
			clobbers: { //需要覆蓋的屬性
				navigator: {
					children: {
						app:{
							path: "myphonegap/plugin/android/app"
						}
					}
				},
			   //省略
				open: {
					path: "myphonegap/plugin/InAppBrowser"
				}
			},
			merges: { //需要合併的屬性
				device: {
					path: 'myphonegap/plugin/android/device'
				},
				navigator: {
					children: {
						notification: {
							path: 'myphonegap/plugin/android/notification'
						}
					}
				}
			}
		}
};


        該模塊是與平臺相關的,現在分析的是android平臺,所以這部分代碼與android平臺相關。platform對象實例提供了一個initialize方法用來執行平臺初始化代碼,id表示不同平臺,clobbersmergescommon下的屬性作用相同,都是一個字面量對象,作爲builder模塊函數的參數用來生成相應模塊對象;二者區別在於clobbers是屬性覆蓋,merges是屬性合併。

        platformcommon類似,因爲與平臺相關,這裏暫時不測試了。

        當所有define語句執行完成也就是模塊定義之後,開始模塊初始化或實例化。先請求主模塊對象,將主模塊對象添加到全局執行環境;之後是一個自執行的匿名函數,context是形參,window是實參。

window.myphonegap = require(‘myphonegap’);

(function (context) {
		if (context.navigator) {
		}

		var channel = require("myphonegap/channel"),
			_self = {
				boot: function () {
							},    [ channel.onNativeReady,channel.onDOMContentLoaded ]);
				}
			};

		channel.onNativeReady.subscribe(_self.boot);
		if (window._nativeReady) {
			channel.onNativeReady.fire();
		}

	}(window));

        第一個if語句中的代碼是對navigator這個變量做處理,讓window下的navigator中的所有屬性變成了它的原型中的屬性。到底有什麼意義,不太明白,看代碼註釋,clobber這個單詞沒看懂什麼意思。

// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
    // We replace it so that properties that can't be clobbered can instead be overridden.
if (context.navigator) {
			var CordovaNavigator = function() {};
			CordovaNavigator.prototype = context.navigator;
			context.navigator = new CordovaNavigator();
		}

        看下面的兩個對象的定義,一個是channel通道模塊,看來下面的代碼涉及到事件訂閱了。_self對象中只有一個函數對象boot, boot函數是初始化引導函數,裏面執行的是channel.join函數,參數爲一個匿名函數和兩個通道對象組成的數組。Join函數代碼比較費勁,它的第二個參數是個通道對象數組,當所有通道事件觸發一次之後,執行第一個參數傳遞過來的函數。

var channel = require("myphonegap/channel"),
			_self = {
				boot: function () {
					channel.join(function() {
						

					}, [ channel.onNativeReady,channel.onDOMContentLoaded ]);
				}
			};

        然後再看看join函數的第一個參數,匿名函數中的內容。先請求buildercommonplatform三個模塊對象,然後根據這三個對象構建了其它的模塊對象。之後執行平臺初始化,觸發onMyphonegapReady事件;最後一個語句,將onDeviceReady事件的觸發,綁定在 channel.deviceReadyChannelsArray中的所有事件觸發之後。

 function() {
						var builder = require('myphonegap/builder'),
							base = require('myphonegap/common'),
							platform = require('myphonegap/platform');

 						builder.buildIntoButDoNotClobber(base.defaults, context);
						builder.buildIntoAndClobber(base.clobbers, context);
						builder.buildIntoAndMerge(base.merges, context);

						builder.buildIntoButDoNotClobber(platform.defaults, context);
						builder.buildIntoAndClobber(platform.clobbers, context);
						builder.buildIntoAndMerge(platform.merges, context);

                        //調用平臺初始化
 						platform.initialize();

                        //觸發onMyphonegapReady通道事件
 						channel.onMyphonegapReady.fire();

						// deviceReadyChannelsArray上的所有事件被觸發之後,觸發第一個參數傳入的匿名函數						       
						channel.join(function() {
							require('myphonegap').fireDocumentEvent('deviceready');
						}, channel.deviceReadyChannelsArray);

					}

        其實立即上面這段代碼的關鍵是立即join這個函數,這個函數是channel提供的。代碼如下:

join: function(h, c) {
            var len = c.length,
                i = len,
                f = function() {
                    if (!(--i)) h();
                };
            for (var j=0; j<len; j++) {
                if (c[j].state === 0) {
                    throw Error('Can only use join with sticky channels.');
                }
                c[j].subscribe(f);
            }
            if (!len) h();
        }

        理解這個函數的關鍵是如何看待f這個對象,給f賦值的是一個函數表達式,函數表達式是不同於函數聲明的,當然函數聲明是無法直接對變量進行賦值的。這個函數表達式中的變量i此時就是這個函數對象的一個屬性了,而且它的初始值就是數組c的長度;函數h就是對象f的另一個屬性;當f函數被調用的時候i1f函數被提交到了channel通道上,也就是說c是個通道數組,當這個通道數組的所有事件都被觸發之後,i才變爲0,此時h函數才被執行。

        對比下JAVA語言實習類似f函數的功能:fh都爲接口,通道事件訂閱是以接口爲參數。

  interface InterfaceF{
  public void f();
  }
  interface InterfaceH{
  public void h();
  }
  ClassF implements  InterfaceF{
  private int i = 0;
  private InterfaceH  interfaceH;
  ClassF(int i  , InterfacH interfacH){
  this.i = i;
  this.interfacH = interfacH;
  }
  Public void f(){
  if(--i == 0) interfaceH.h();
  }
  }
InterfaceF instanceF = new ClassF(c.length, instanceH);







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章