JSI小试牛刀——Native同步调用JS代码
2023-10-21 12:41:59
前言
上一篇有说到在有了JSI之后,JS和Native同时持有一个HostObject,那么JS和Native之间就有了同步调用的基础条件。实际上,在现在的RN(以0.59版本为例)中,已经实现了JS向Native代码的同步调用,在iOS中,可以通过宏RCT_EXPORT_BLOC…
实现。
原理
Native同步调用JS代码的原理其实很简单,就是Native将要执行的任务封装成一个函数,然后将这个函数作为参数传递给JS,JS收到这个函数后,将其放入消息队列中,然后调用Native提供的回调函数来通知Native函数已经放入消息队列。Native收到回调后,将当前线程阻塞,等待JS执行完任务并返回结果。
实现
在iOS中,Native同步调用JS代码的实现需要用到以下几个宏:
RCT_EXPORT_BLOCKING_SYNCHRONOUSLY
:此宏用于声明一个同步调用JS代码的Native方法。RCT_EXPORT_METHOD
:此宏用于声明一个Native方法。resolve
:此函数用于将结果返回给Native。JSThread
:此类用于获取当前的JS线程。JSRUNLOOP_IS_CALLING_JS
:此宏用于判断当前线程是否是JS线程。
下面是一个Native同步调用JS代码的示例:
@implementation NativeModule
RCT_EXPORT_BLOCKING_SYNCHRONOUSLY(NSString *, multiply:(nonnull NSNumber *)a withB:(nonnull NSNumber *)b) {
// 获取JS线程
JSThread *jsThread = [JSThread currentJSThread];
// 创建一个函数并将其作为参数传递给JS
__block NSString *result;
RCTExecuteOnJSCallQueue(jsThread, ^{
result = [self _multiply:a withB:b];
// 调用回调函数通知Native函数已经放入消息队列
resolve(result);
});
// 阻塞当前线程,等待JS执行完任务并返回结果
while (JSRUNLOOP_IS_CALLING_JS()) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
return result;
}
- (NSString *)_multiply:(NSNumber *)a withB:(NSNumber *)b {
return [NSString stringWithFormat:@"%d", [a intValue] * [b intValue]];
}
@end
在JS中,可以这样调用上面的Native方法:
const result = NativeModules.NativeModule.multiply(1, 2);
效率
Native同步调用JS代码的效率并不高,因为Native线程在等待JS执行任务期间是阻塞的。因此,不建议在Native代码中频繁使用同步调用JS代码。
性能
Native同步调用JS代码的性能与JS线程的执行效率密切相关。如果JS线程执行效率低,那么Native同步调用JS代码的性能也会很低。因此,在使用Native同步调用JS代码时,应确保JS线程的执行效率足够高。
线程
Native同步调用JS代码时,Native线程和JS线程是分开的。Native线程负责执行Native代码,JS线程负责执行JS代码。当Native线程调用JS代码时,Native线程会将要执行的任务封装成一个函数,然后将这个函数作为参数传递给JS线程。JS线程收到这个函数后,将其放入消息队列中,然后调用Native提供的回调函数来通知Native函数已经放入消息队列。Native收到回调后,将当前线程阻塞,等待JS线程执行完任务并返回结果。
消息队列
消息队列是JS线程用来处理任务的队列。当Native线程调用JS代码时,Native线程会将要执行的任务封装成一个函数,然后将这个函数作为参数传递给JS线程。JS线程收到这个函数后,将其放入消息队列中。然后,JS线程会依次从消息队列中取出任务并执行。
多线程
Native同步调用JS代码时,Native线程和JS线程是分开的。Native线程负责执行Native代码,JS线程负责执行JS代码。因此,Native同步调用JS代码时,可以实现多线程。
任务
Native同步调用JS代码时,Native线程会将要执行的任务封装成一个函数,然后将这个函数作为参数传递给JS线程。JS线程收到这个函数后,将其放入消息队列中。然后,JS线程会依次从消息队列中取出任务并执行。