不知从什么时候起,移动端App开发,采用Native仍是使用Web的争论不绝于耳。两者的优缺点再也不赘述。Web App固然是开发者期待的理想结果,可是因为Native App在用户体验上的绝对碾压,大部分移动端App仍是采用Native的方式,少数架构复杂、对Web依赖较多的App,会采用一种称为Hybrid(Web + Native)的开发方式,在iOS上,Native经过-[UIWebView stringByEvaluatingJavaScriptFromString:]调用Web,而Web则是经过设置WebView iframe的src,搭建JSBridge进行通信。因为微信和手机支付宝的的成功,Hybrid App这种开发方式确实引发了关注,但从我这么一个最底层iOS开发者的技术角度来讲,这种JSBridge的通信方式,实在不是特别高明,能解决的场景也十分有限。css
前几天FB正式推出了React Native。因为惯性思惟,我总想着往它身上贴个「Web」或者「Native」或者「Hybrid」的标签,但是贴上去扯下来,并无一个适合的标签。事实上,React Native从新定义了一种新的模式。html
在说React Native以前,让咱们以WebKit为例,先扯一扯一个浏览器引擎的工做流程。从下图能够看出,一个网页的生命周期,大体经历了加载、解析、排版、绘制(JS引擎暂时不提)。前端
接触过iOS平台上的简易的浏览器引擎,大体的工做流程,也是如此。因为加载流程涉及网络模块,部分排版和渲染流程涉及Native UI控件,为解决不一样平台的差别性,通常是抽象接口,由不一样平台实现各自的网络模块和网页的绘制。react
简单来讲,一个浏览器渲染引擎,其实就是将网页从服务器或者本地load下来,用一套规则解释这个网页,最后用平台最舒服的方式,展示到屏幕上去。git
因为对浏览器印象深入,这是React Native给个人第一印象。因为我对前端的了解,只停留在html和Javascript的简单语法上,彻底不知ReactJS为什么物,因此我只能尝试着从开源的iOS React Native的OC端代码,解释一下。github
得益于JavascriptCore,React Native可以抛弃WebView直接运行JS,在React Native,OC层只负责控制程序生命周期,以及提供平台Native控件的工做;而JS层则负责提供数据,响应交互事件,充当了DataSource和Delegate的角色。react-native
这里的通讯,是指JS和OC之间的通讯。浏览器
前面已经提到,OCBridge是利用JavascriptCore直接调用JS代码的。OC层实现这个类的是RCTBridge,目前的代码是使用RCTContextExecutor做为具体的执行者。JavascriptCore是iOS7才开放的接口,不过目前的代码还有另一套RCTWebViewExecutor,里面用的是经过UIWebView调用JS,多是为了之后兼容旧版本的iOS。使用JavascriptCore最显而易见的优点就是,整个执行过程均可以在后台线程执行,事实上RCTContextExecutor单独开了一个名为「com.facebook.React.JavaScript」的线程,供本身使用。服务器
上面只提到OCBridge,那JSBridge呢?微信
答案是,没有JSBridge。前面提到,OC层提供Native控件,JS层更多地是扮演DataSource和Delegate的角色。回想一下UITableview的使用,为UITableview设置DataSource和Delegate以后,使用者并不须要关心UITableview是如何被建立绘制,以及如何监听点击长按之类的交互事件。同理,JS层做为使用者,并不须要关心Native事件是如何触发的,须要关心的是,当事件触发时该如何响应。因此,一个本来须要双向通讯的机制,被简化成单向通讯。
这个机制,能够经过查看 -[RCTBridge enqueueJSCall:args:]这个函数的Callers来验证(这个函数是OC层调用JS的入口函数),它的 Callers包括了:Device Event(如先后台切换)、Input State(如控件Value改变)、Timer回调、Touch事件回调等等。
那JS层是如何实现调用OC层的呢?是经过返回值。在事件触发OC层调用JS以后,会得到一段JSON数据做为返回值,OC层只须要按照协议,解析这段JSON数据,依次调用Native代码便可。
JS调用OC的协议,是-[RCTBridge setUp]的时候,经过 RCTRemoteModulesConfig()建立并传给JS层的。 RCTRemoteModulesConfig()主要作了几个事情:
当JS返回JSON数据时,实际上返回了一段包含了moduleID和methodID的队列,OC层按照协议的约定,执行对应方法。
至于OC调用JS的协议,也是经过module、method来标识的。不过这些module、method都是OC层写死的字符串,应该是和JS强绑定的,没有啥特殊之处。
浏览器引擎,离不开的就是dom tree 和render tree。简单来讲,dom tree 是根据源数据解析而来的,包含了原始的节点信息;而render tree 则是dom tree + css。排版的目的,就是生成render tree,肯定每一个节点在屏幕上的大小位置。
在React Native中,解析过程是在JS层完成的,原理未知。在OC层,RCTUIManager负责将JS层的解析结果,映射到OC层的视图层级,它自己不作任何的解析操做,只是提供方法,让JS层调用而已。最终dom tree映射到OC层的结果,是一棵「RCTShadowView tree」。RCTShadowView这个名字也起得颇有意思,它不是真正展示的视图,只是一个映射结果而已,每个RCTShadowView对应一个真正的视图。RCTShadowView的另外一个意义在于,它拥有一个成员变量cssNode,能够经过FB的开源项目css-layout(代码里面可贵一见的两个C文件),完成排版。剩下的细节工做,就交给RCTShadowView对应的真实视图了。
其实一开始并无打算看源码的,只是由于Demo中一张图片没法显示,让我不得不调试图片下载模块来肯定问题 -_-|||(图片下载使用的是NSURLSession,这货也是iOS7才有的接口,看来React Native还没打算支持旧版本的iOS)。时间匆忙,水平有限,确定错误连篇,还望指正。