“站在10年研发路上,眺望前端未来”:读后感

以下内容感觉都是嘴炮,没啥干货,也没啥源码,就是自己的一点乱七八糟的想法,甚至可能是个人单方面的yy。。。我还是不归类在搬砖里,归类在扯淡里吧

偶然间看到了这篇阿里大神的采访稿,看过之后,作为一个对前端抱有极大兴趣客户端开发,作为一个不太懂前端的小白,依然觉得好赞。

站在10年研发路上,眺望前端未来

以下为原文引用

App混合开发的优缺点有哪些?是否会成为主流?

桐木:混合开发主要是为了实现动态化和节约开发成本,但WebView里跑的部分无论如何也很难达到Native的性能和体验。目前很多技术的发展其实都是在改造WebView,试图甩掉一些包袱或者说历史负担。有人可能会奇怪,WebView有哪些历史负担呢?我们可以来仔细看看:

首先,是标准兼容上的包袱。由于WebView作为一个通用的浏览器内核,本身要求具备向前兼容性,比如虽然用flexbox布局浏览器可以更高效地layout,但为了兼容它仍然必须得能认得浮动布局、相对定位布局甚至表格布局。这些逻辑交织在一起非常复杂,牵一发而动全身。假设我现在fork一个新的WebView出来,裁减掉flexbox之外的支持,就大大降低了layout逻辑的复杂度,即使不做优化就已经能快不少了,更何况情况变简单以后还能够针对flexbox布局做专门的优化,获得更大的性能提升。

其次,浏览器的内部机制以及js语言在设计上,其实也有一些历史包袱。比如浏览器从一开始设计,js engine和dom engine就是两块独立的黑盒,js调用dom时相当于一次rpc调用,每次调用都会涉及上下文的保存和恢复。同时,js excute和dom render是跑在一个线程里的,即使两者没有调用关系,dom也必须等js执行完毕才能render。这两件事的结果就是网页在运行过程中会在这两个黑盒之间来回切换,各种上下文切换,各种互相等待,这样一来掉帧就在所难免了。所以,如果我们能够让js engine和dom engine在执行层面能够打通,变rpc调用为本地调用,就能加快不少。更进一步来说,如果能够有效利用多核,把js excute和render在一定条件下并行起来,或者把style resolving和layout并行起来,也能提升新性能。

再次,WebView本身确实也在越变越快,但有些OS的限制或者一些设备老旧WebView的存在,会导致碎片问题,这也在拖慢我们的脚步。这个大家比较熟悉了,例如iOS的Nitro、WKWebView之于UIWebView,还有Andorid4.4之后的Chromium WebView之于之前的WebKit WebView。

老郭的BeeFramework/Samurai、阿里的birdnest,是在甩前两项包袱,一方面取Web标准的子集,一方面把所有东西都拉到Native的runtime里执行;FB的React Native和阿里的Weex,主要在甩第一项包袱(部分优化了第二项);Mozilla的Servo致力于并行化和GC,主要是在甩第二项包袱;Intel的crosswalk、微信的X5、阿里的UCWebView等,是在一定范围内甩第三项包袱……大家为了甩掉这些包袱,都提出了不同的解决方案。

不论大家走哪条路,有一个共识还是大家都找到了的,那就是看齐Web的几个标准。因为Web的技术体系在UI的描述能力以及灵活度上确实设计得很优秀的,而且相关的开发人员也好招。所以,如果说混合开发指的是Native里运行一个Web标准,来看齐Runtime来写GUI,并桥接一部分Native能力给这个Runtime来调用的话,那么它应该是一个永恒的潮流。

对fe有兴趣的一个外行

我自己在刚毕业的时候做游戏,做过半年时间的cocos2dx-lua的开发,早在3年前,就已经产生了这种,纯lua脚本动态更新整个游戏app的解决方案,这种脚本解释驱动native的方案,当时就已经让我一个刚毕业的新人产生无限的探索求知欲望。

后来转行iOS,因为业务原因,接触到了和排版相关的工作内容,发现我们的文字排版引擎,都很类似浏览器内核的webcore部分,将UI描述文件JSON(内容类似HTML,CSS)通过解析生成数据结构(类似dom树的东西),再经过排版计算(类似flexbox),生成了渲染结构(类似render树的东西),再进行渲染。

再后来接触了JSPatch,React-Native,这些看起来都能实现动态更新这一目标,但深入思考会觉得这里面很多思路都是完全相通的

  • 脚本去驱动native(C++native,源生平台native,runtime动态native)
  • 界面描述语言组织布局和渲染

怀着对这种动态化hybrid方案的极度好奇,对于脚本驱动native,对于html+css驱动布局渲染,到底是怎么实现的,极大地求知欲,我对前端也产生了浓厚的兴趣

我从来不认为什么H5开发与Native开发是冲突或者对立的,这俩谁抢谁饭碗的问题,就像引文最后这一段所说的,native与web,我觉得应该是水乳交融的状态。

Hyrbid的第四个包袱

我还很不了解FE,但从客户端的角度看这个问题,也有点自己的琢磨,也不知道对不对,真的很希望能有专业人士帮我指正一下,同时我也会尽可能的弥补自己在FE方面知识的欠缺

大神文章中提到的三个包袱,都是纯webview的情况下的包袱,如果进入了web与native,hybrid混合开发的模式下,我觉得还会有第四个包袱
(此处经@bang哥修正,对原来的表述有所修改)

rpc不只存在于js与dom之间,还存在于js环境与native环境两个环境的协议沟通。

既然是hybrid,那离不开na的工作,na的运行环境与js的运行环境是完全独立的两个环境,虽然在一个app内,但二者之间也不是那么顺畅的无缝调用,都依赖于一个桥

  • 基于webview hybrid依赖于webview的JSbridge设计
  • cocos2dx-lua 依赖于tolua++ 半自动生成的 lua/C++bridge设计
  • 基于JavaScriptCore的桥接API的JSbridge设计

桥的设计与调用方案各不相同,但走过这个桥也是有开销和成本的,并不是随便调用的,JSCore在app环境内是一个JS虚拟机+不同上下文,而Na的环境也会有安卓的java虚拟机,iOS/C/C++的直接内存环境,不同的环境之间,通信传递数据,面临的都是rpc的切换开销。如果想减少这个包袱,那就应该尽可能的减少web-native通信次数,可能的布局运算,逻辑运算,都先放在web这个环境的内部。

如果拿cocos2dx-lua对比react-native来说,cocos2d-x确实是以脚本驱动native实现了动态更新的目标,但是缺失的确是一整套UI描述语言的布局能力,也就是第一个包袱,正因为完全缺失了第一个包袱,所以才必须频繁的切换luaengine(类比jsengine)与native的上下文,用lua来使用na的布局代码方案进行界面编写,从而造成了我说的第四个包袱的问题(不再是脚本与dom切换,而是脚本与native切换频繁)。

但cocos2dx有个特点,得益于lua这种语言的C内核解释器的运行效率以及以及同为C/C++语言的native部分的相似性,这部分开销在普通的2D简单UI型游戏的开发上,目前看还没啥瓶颈,但是,遇到COC这种同屏多兵种每个兵种各自有独立AI运算的情况下,就会有吃力(以前游戏组遇到的case,不过具体情况还有点复杂,不太好完全归结于第四个包袱)

而react-native正如文中所说,一方面着手优化第一个包袱,而且还以React.js的virturl dom的特点优化了第二个包袱,并且由于在js层处理了布局运算,从而减轻了我说的第四个包袱的压力

(以下是@彩虹的修正)

性能上,不仅第四个包袱js-native bridge有性能问题,本身JavaScriptCore也会存在性能问题,不同的设备,安卓or iOS不同系统版本,在JavaScriptCore能力差得情况下,RN也会面临性能困境

RN虚拟出了一套diff virturl dom,是放在内存中的一套配置文件,这部分内存中的数据配置,直接生效在native,也就是说,这个dom环境其实也就是na环境,js与dom的切换包袱存在,但这一块其实不属于我说的js与native bridge的第四个切换包袱,

根据彩虹的修正,可以理解RN的dom环境其实就是na环境,是一个na布局+渲染的环境,而我第四个包袱提到的na环境,严格上讲是native-bridge所桥接的那块na环境,这两个环境都是na,如果切换js环境,都存在rpc,这两个环境本身并不直接互通

我对前端的了解一知半解,这些理解,也不知道说的对不对,片面不片面,最近也在学习前端,希望能补上自己这块知识点的空白,也希望能得到前端同学的指导

我觉得Hyrid,确实就是引文所说,如果说标准webview不能满足性能或者native独有硬件设备上的需求,那么我们就参照借鉴web标准,在native内重新打造一个,经过优化包袱后的web native runtime,毕竟web的标准从灵活性上经历了那么久的考验,而客户端如果能改变一些内核策略,甩掉一些包袱,争取到适应当下移动设备性能并且兼顾动态性的最优体验,那就真的是客户端与前端的水乳交融的hybrid了

以上内容感觉都是嘴炮,没啥干货,也没啥源码,就是自己的一点乱七八糟的想法。。。我还是不归类在搬砖里,归类在扯淡里吧