深入领略React Native焦点道理(React Native的桥接((2)

这很是直观,只需要从指定的任何提供措施中加载源代码,凡是在开拓进程中从打包措施中加载源代码,在出产情况中从磁盘加载。

执行JavaScript代码

一旦所有工作筹备停当,我们可以在JS虚拟机中加载应用的源代码,复制代码,理会并执行它。在第一次执行时需要注册所有CommonJS模块而且需要进口文件。

JSValueRef jsError = NULL; JSStringRef execJSString = JSStringCreateWithCFString((__bridge CFStringRef)script); JSStringRef jsURL = JSStringCreateWithCFString((__bridge CFStringRef)sourceURL.absoluteString); JSValueRef result = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, &jsError); JSStringRelease(jsURL); JSStringRelease(execJSString);

JavaScript中的Modules

在JS侧我们此刻可以通过react-native的NativeModules拿到前面的JSON设置信息组成的module:

深入明确React Native核心原理(React Native的桥接(

它运行的方法是当你挪用一个要领的时候它被放到一个行列,包罗module的名称,method的名称以及所有的参数,在JavsScript执行的最后这个行列会给原生模块执行。

挪用周期

此刻假如我们用上面的代码挪用module,它将会是这个样子的:

深入明确React Native核心原理(React Native的桥接(

挪用必需从native开始,native挪用JS(这张图只是截取了JS运行的某个时刻),在执行进程中,因为JS挪用NativeModules的要领,它把这个挪用入队,因为这个挪用必需在原生何处执行。当JS执行完后,原生模块遍历入队的所有挪用,然后当它执行这些挪用后,通过桥接举办回调(一个原生模块可以通过_bridge实例来挪用enqueueJSCall:args:),来再次回调JS。

(假如您一直在存眷该项目,已往也有来自native-> JS的挪用行列,该挪用行列会在每个vSYNC上分配,但为了缩短启动时间已将其删除)

参数范例

native到JS的挪用很容易,参数被NSArray通报,我们将其编码为JSON数据,可是对付JS对native的挪用,我们需要native的范例,为此我们查抄根基范例(ints,floats,chars...)可是就像上边提及那样,对付任何工具(布局),运行时我们不会从NSMthodSignature得到足够的信息,所以我们把范例生存为字符串。

我们利用正则表达式从method签名中提取范例,并利用RCTConvert类来实际转换工具,默认环境下它为每种范例都提供了要领,而且实验将JSON输入转换为所需要的范例。

除非是一个struct,不然我们利用objc_msgSend动态挪用该要领,因为arm64上没有objc_msgSend_stret的版本,因此我们利用NSInvocation。

转换完所有参数后,我们将利用另一个NSInvocation来挪用方针module和method。

例子:

// If you had the following method in a given module, e.g. `MyModule` RCT_EXPORT_METHOD(methodWithArray:(NSArray *) size:(CGRect)size) {} // And called it from JS, like: require('NativeModules').MyModule.method(['a', 1], { x: 0, y: 0, width: 200, height: 100 }); // The JS queue sent to native would then look like the following: // ** Remember that it's a queue of calls, so all the fields are arrays ** @[ @[ @0 ], // module IDs @[ @1 ], // method IDs @[ // arguments @[ @[@"a", @1], @{ @"x": @0, @"y": @0, @"width": @200, @"height": @100 } ] ] ]; // This would convert into the following calls (pseudo code) NSInvocation call call[args][0] = GetModuleForId(@0) call[args][1] = GetMethodForId(@1) call[args][2] = obj_msgSend(RCTConvert, NSArray, @[@"a", @1]) call[args][3] = NSInvocation(RCTConvert, CGRect, @{ @"x": @0, ... }) call()

线程

正如以上提及那样,每个module默认都有一个GCD行列,除非它通过实现-methodQueue要领或将methodQueue属性与有效行列归并来指定要在哪个行列运行。ViewManagers*是破例(扩展了RCTViewManager),将默认利用Shadow Queue,而非凡方针RCTJSThread仅是一个占位符,因为它是线程而不是行列。

(其实View Managers不是真正的破例,因为基类显式的将Shadow Queue指定为方针行列了)

当前线程法则如下:

-init和-setBridge:担保在主线程执行

所有export的要领担保在方针行列执行

假如你实现了RCTInvalidating协议,则还可以确保在方针行列上挪用了invalidate

无法担保在哪个线程挪用-dealloc

当吸收到JS的一批挪用时,这些挪用会按方针行罗列办分组,并行挪用:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsjyws.html