React Native技術剖析(一)

來源:互聯網
上載者:User

標籤:gif   parent   option   思路   array   param   ica   接下來   utf8   

前言

React Native(簡稱RN)的由來、優勢、安裝使用等等不在這裡囉嗦,可以自行Google/百度。筆者整理了一下之前學習RN過程中記錄的筆記,結合RN原始碼來分析RN架構裡面的一些技術思路,這對於理解和更好地使用RN都是很有益處的。由於水平有限,肯定有一些理解不對的地方歡迎指正。
今天主要講一下,RN初始化過程是什麼步驟,都做了哪些事情。

RN初始化過程

以iOS為例,RN的渲染主要在RCTRootView中,初始化代碼非常簡單,就是建立RootVIew對象. (由於函數調用層次比較深,一層層講解很容易不清楚當前在那個函數,請讀者諒解)

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation                                                 moduleName:@"LarkRN"                                            initialProperties:nil                                                 launchOptions:launchOptions];

我們看一下RCTRootView的initWithBundleURL函數做了什麼:
函數中建立一個Bridge對象,並調用initWithBridge函數。

- (instancetype)initWithBundleURL:(NSURL *)bundleURL                       moduleName:(NSString *)moduleName                initialProperties:(NSDictionary *)initialProperties                    launchOptions:(NSDictionary *)launchOptions{  RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL                                            moduleProvider:nil                                             launchOptions:launchOptions];      return [self initWithBridge:bridge moduleName:moduleNameinitialProperties:initialProperties];}

Bridge對象建立過程中又調用了[self setUp],setUp函數調用createBatchedBridge函數建立了一個BatchedBridge對象

- (void)createBatchedBridge{  self.batchedBridge = [[RCTBatchedBridge alloc] initWithParentBridge:self];}

BatchedBridge對象初始化中又調用了[self start],Start函數調用moduleConfig函數

    config = [weakSelf moduleConfig];

BatchedBridge對象的moduleConfig函數主要是收集所有原生模組配置資訊,返回格式化字串。

NSMutableArray<NSArray *> *config = [NSMutableArray new];  for (RCTModuleData *moduleData in _moduleDataByID) {    if (self.executorClass == [RCTJSCExecutor class]) {      [config addObject:@[moduleData.name]];    } else {      [config addObject:RCTNullIfNil(moduleData.config)];    }  }  return RCTJSONStringify(@{    @"remoteModuleConfig": config,  }, NULL);

每個原生模組的配置資訊由RCTModuleData 對象config屬性管理,config是個數組,其中的元素依次為模組名,匯出常量數組,匯出函數數組,匯出非同步函數(類型為RCTFunctionTypePromise的函數)索引數組

NSDictionary<NSString *, id> *constants;NSMutableArray<NSString *> *methods;NSMutableArray<NSNumber *> *asyncMethods;  NSMutableArray *config = [NSMutableArray new];  [config addObject:self.name];  if (constants.count) {    [config addObject:constants];  }  if (methods) {    [config addObject:methods];    if (asyncMethods) {      [config addObject:asyncMethods];    }  }

BatchedBridge對象Start函數調用injectJSONConfiguration函數

  [weakSelf injectJSONConfiguration:config onComplete:nil]

BatchedBridge對象injectJSONConfiguration函數就是向JSC中添加一個全域變數__fbBatchedBridgeConfig

 [_javaScriptExecutor injectJSONText:configJSON                  asGlobalObjectNamed:@"__fbBatchedBridgeConfig"                             callback:onComplete];

接下來執行BatchedBridge對象的executeSourceCode函數,執行RN Bundle檔案(JS代碼)

 [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:^(NSError *loadError)  {…此處省略}

BatchedBridge對象的executeSourceCode函數調用JSC的executeApplicationScript函數來運行JS代碼

 [_javaScriptExecutor executeApplicationScript:script sourceURL:url onComplete:^(NSError *scriptLoadError) {…}

JSC對象的executeApplicationScript函數將下載的RN Bundle檔案放入JSC中執行

    RCTJSCExecutor *strongSelf = weakSelf;    JSValueRef jsError = NULL;    JSStringRef execJSString = JSStringCreateWithUTF8CString((const char *)script.bytes);    JSValueRef result = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, _bundleURL, 0, &jsError);    JSStringRelease(execJSString);

JS的BatchedBridge對象實際上是MessageQueue對象,使用前面的__fbBatchedBridgeConfig(原生模組配置列表)變數進行初始化

    constBatchedBridge=new MessageQueue(        ()=>global.__fbBatchedBridgeConfig    );

MessageQueue對象的初始化過程中建立一個RemoteModules屬性

    lazyProperty(this,‘RemoteModules‘,()=>{        Let {remoteModuleConfig}=configProvider();        Let modulesConfig=this._genModulesConfig(remoteModuleConfig);        Let modules=this._genModules(modulesConfig);        this._genLookupTables(            modulesConfig,this._remoteModuleTable,this._remoteMethodTable        );        returnmodules;    });    _genModules(remoteModules){        Let modules={};        remoteModules.forEach((config,moduleID)=>{        Let info=this._genModule(config,moduleID);        if(info){            modules[info.name]=info.module;        }        });        Return modules;    }

MessageQueue對象的_genModules函數產生模型資訊對象,key值為模型名,如果模組沒有匯出任何屬性(常量或函數),則僅記錄模組ID;處理模型中匯出的函數,對函數進行封裝。

    _genModule(config,moduleID):?Object{        Let moduleName,constants,methods,asyncMethods,syncHooks;        if(moduleHasConstants(config)){            [moduleName,constants,methods,asyncMethods,syncHooks]=config;        }else{            [moduleName,methods,asyncMethods,syncHooks]=config;        }        Let module={};        Methods && methods.forEach((methodName,methodID)=>{        Const isAsync = asyncMethods && arrayContains(asyncMethods,methodID);        Const isSyncHook = syncHooks && arrayContains(syncHooks,methodID);        Const methodType=isAsync? MethodTypes.remoteAsync:        isSyncHook ? MethodTypes.syncHook:        MethodTypes.remote;        module[methodName]=this._genMethod(moduleID,methodID,methodType);        });        Object.assign(module,constants);        if(!constants&&!methods&&!asyncMethods){            module.moduleID=moduleID;        }        return{name:moduleName,module};    }

MessageQueue對象的_genLookupTables函數產生模組名檢索表和函數檢索表

    _genLookup(config,moduleID,moduleTable,methodTable){        Let moduleName,methods;        if(moduleHasConstants(config)){            [moduleName,,methods]=config;        }else{            [moduleName,methods]=config;        }        moduleTable[moduleID]=moduleName;        methodTable[moduleID]=Object.assign({},methods);    } 

MessageQueue對象registerCallableModule註冊JS端可調用模組,記錄每個模組名和可用的函數列表,供原生端調用

    BatchedBridge.registerCallableModule(‘Systrace‘,Systrace);    registerCallableModule(name,methods){        this._callableModules[name]=methods;    }

MessageQueue對象初始化完成後,會放入到一個全域變數”__fbBatchedBridge”中,供後續使用。

    Object.defineProperty(global,‘__fbBatchedBridge‘,{value:BatchedBridge});

到此,RN初始化過程全部結束。簡單來說,就是收集原生和JS模組配置資訊,然後產生每個模組及其可用函數的檢索表, 並放入JSC中全域變數中儲存起來。

React Native技術剖析(一)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.