既昨日给大家介绍了过去一年里 Weex 业务规模不断扩大, 业务复杂度不断上升, 给 Weex 带来了哪些技术挑战, 以及 Weex 在技术架构和设计上做了哪些升级来应对这些挑战
今天, 我们会从内核角度切入, 为大家继续带来 Weex 技术演进之路的分享
内核挑战
随着 Weex 业务规模的扩大和业务覆盖场景的丰富, Weex 不仅在性能稳定性上面临越来越大的挑战, 在安全隔离方面, 也遇到前所未有的风险
性能方面: 例如, 去年的双 11 和今年双 11 主会场规模对比, 去年整个会场的 JS Bundle 大小控制在 250K 以内, 今年主会场页面平均达到 500K+, 业务复杂度增加了接近 2 倍, Weex 的加载性能跟 JS bundle 的大小基本成正相关;
稳定性方面: 业务场景覆盖面的提升, 从原来的偏展示的场景到偏交互场景的业务, 以及一些常规业务的接入; 新的业务场景, 必然导致新的稳定性方面的挑战, 事实也如此;
富交互: 引入 GcanvasAR/VR 等富交互场景, 对 Weex js-native 的通信效率要求极高;
安全性: 旧引擎的安全漏洞的问题, 以及业务之间存在相互污染, 无法做到安全隔离的问题;
证书问题: Yoga 引擎的证书授权问题;
内核技术演进
从三个方面来阐述 Weex 在内核重要方向的演进: JS 引擎 Layout 引擎 WeexCore 架构的演进;
JS 引擎: 我们的目标是更快更稳定更安全更小; 其一: 我们投入大量资源在 JS 引擎的优化上, 从 JS 引擎的替换, 由原来旧版本的 V8 换成最新版本 JavaScriptCore; 其二: 我们开创性地将 JS Runtime 运行于独立的进程里, 不仅保证主进程的稳定性, 而且加入了智能恢复的能力; 其三: 重新考虑 Weex 业务隔离的安全问题, 开发设计了多 Context 隔离的方案, 保证避免业务间互相污染; 其四: 瘦身, 包的精简;
Layout 引擎: Weex 项目成立以来, 我们一直借用的 Facebook 的 Yoga 项目作为我们的布局引擎, 但是 Layout 引擎对于 Weex 项目又是如此重要, 所以, 我们今年 10 月份开始计划开发全新的 Layout 引擎开发的项目, 来替换 yoga 引擎第一, Layout 引擎作为核心模块, 我们希望去主导演进的路线; 第二, Facebook 的证书风险不能回避; 所以我们决定重新开发自己的 Layout 引擎, 并争取做到更高性能, 支持更多布局方式;
WeexCore 架构: 今年我们讨论最多的就是 Weex 后续如何演进, 在性能稳定性方面如何做的更优, 在复杂业务的支持方面如何做的更好 WeexCore 首先是高性能的, 用以满足更复杂场景业务开发, 以及提升业务开发体验; 其次是一个跨平台的内核, 从 DSL 的跨平台到内核的跨平台
JS 引擎技术
众所周知, JS 引擎至于 Weex 至关重要, 是 Weex 最重要的一个核心模块, 2017 年, 我们在 JS 引擎的投入也是非常大:
2017-3 月~2017-7 月: 对最新版本的 V8 和最新版本的 JavaScriptCore 做来全面的 profile, 让 profile 数据告诉我们去选择哪个引擎作为 Weex 新一代的 JS 引擎经过 4 个月的努力, 终于将最新版本的 JavaScriptCore 在手机淘宝正式版本上线, 同时 Weex 也是第一个将 JavaScriptCore 引擎 (javascriptcore 引擎 apple 维护的, 很少在 android 平台商业化过) 集成到手机淘宝这样体量的 App 中, 中间遇到的兼容性的问题也是我们最大的挑战最终性能提升还是比较明显的, 手淘上 Weex 整体业务首屏加载时间提高了 40% , 并全面支持 ES6 特性;
2017-7 月~2017-10 月: 新版本的 JavaScriptCore 上线以后, Weex 的稳定性 native crash 占比 5% 左右, 按照手淘的稳定性要求 (<1%) 还是有比较大的差距, 这个将是我们 2017 年双十一前最大的挑战当时 Weex 稳定性小组的同学出于焦虑中, 随着双十一临近, 不断有新 Weex 业务上线, 伴随着冒出一些的兼容性的问题出来, 始终看不到收敛的趋势一方面, 我们正向地去解决这些适配的问题, 另一方面, 我们也讨论如何彻底地解决 JS 引擎的稳定性的问题; 后来, 我们想到将 JS 引擎独立运行到单独的进程里去, 这个方案带来最大的好处, 就是 Weex 业务的 crash 不会影响主程序的稳定性; 这个方案也成了双十一 Weex 稳定性保障的救命稻草最终这个方案在 10 月份前正式上线, 效果非常明显, Weex 引起的 native crash 占比一下子从 5% 下降到 0.5% 左右
2017~11 月~至今: 双十一之后, JS 引擎项目主要在做两个事情, 一个 Weex 安全隔离方案, 另一个是包精简优化方案; Weex 安全隔离方案主要解决页面隔离的问题, 双十一当天也遇到一个非常严重的全局污染的案例, 某个业务不小心污染了全局对象, 导致所有的 Rax 的页面出现白屏的问题; 针对这些案例, 我们重新设计了 Weex 安全隔离的方案, 目前安全隔离方案已经内部灰度中, 预计 2 月份正式社区发布; 包精简优化方案: 主要解决 Weex sdk 集成了最新版本的 JavaScriptCore 以后, 包大小增大一倍的问题(4.2M 左右), 包的增大直接增大了 App 接入的门槛, 特别是对包大小非常敏感的 App 目前同步一下信息: 精简优化方案目前也基本开发完毕, 预计可以减少到 2.6M 左右, 预计也是 2 月份上线;
独立进程化
问题
同一个进程中, 与主 App 存在资源竞争, 尤其是内存问题比较突出, JavaScriptCore 虽然执行性能提升了, 但对内存的消耗也同时增大不少, 所以替换成 JSC 以后, Weex 的内存问题导致 Crash 也明显上升;
独立进程的方案本身比较 Hack, 再加上 Android 生态的碎片化, 开发过程中也遇到很多适配问题, 比如在某些机型上独立进程拉不起来, 导致业务渲染失败;
JavaScriptCoe 引擎本身对 android 平台适配比较差, 没有比较大体量的 App 在线上应用过;
优势
进程独立以后, 完全和主 App 的进程隔离, 避免了进程资源竞争导致 crash 的问题, Weex 的 crash 也不会引起主进程的 crash;
Weex 原有的三个线程架构, JS 线程任务被并行成两个, JS 独立的进程和原来 JS 线程, 整体增强了 JS 任务执行的并发性, 抵消了方案本身的 IPC 通信的性能损耗;
独立进程后, 我们加入了自修复的能力, 增强了 JS Runtime 进程的自动重置功能, 解决 JS Runtime 异常后的无法自动恢复的问题, 极大地保障业务的稳定性;
SandBox 机制
Weex 原有的设计, 所有 Weex 页面包括 JSFrameWork 都是运行在同一个 JS Context 里, 并在 JS 层面, 对全局的 JS 变量做了 freeze 操作, 防止被其他业务页面污染这个设计主要还是出于高性能和安全性的综合考量
2017 年双十一出现的全局污染的问题, 让我们重新思考 Weex Context 的安全隔离的方案, 安全稳定高于一切经过新的讨论后, 我们决定针对每个 Weex 页面都创建一个 JS Context 作为独立的运行环境, 页面依赖的全局对象由 Global Contex 统一生层并传递给每个页面的 Contex; 传输的过程, 我们做了两个非常重要的操作:
1)对传输的对象做 freeze 操作;
2)在 javaScript 引擎层面, 通过 native 的 SetPrototype 接口切断原型链的关系; 这样就彻底解决了页面间互相污染的问题该方案预计 2 月份正式上线
Layout 引擎
全新的 Layout 引擎参考了 Google 的 FlexLayout 的算法流程, 重新实现了 Weex 的 Flex 布局, 目前性能和功能方面基本和 yoga 保持一致, 后续会做一些性能优化至于未来如何演进, 团队同学讨论几个关键的步骤:
自主开发全新的高性能的跨平台 Layout 引擎, 统一由 C++ 实现, IOS/android 两端复用同一套代码;
扩展更多的布局方式, 比如 Gird 布局 Absolute 布局等
编译器或服务端做预布局, 提升端测的布局效率等;
该方案预计 2 月份正式上线
WeexCore 架构升级
Weex 作为一个跨平台的开发框架, 在 Android/ IOS/html 三端实现跨平台一致性非常重要目前 Weex 核心渲染流程分平台实现, 不仅多人维护导致不可避免的逻辑实现差异, 而且对于后续新平台扩展成本也非常高 (核心渲染流程需要重新实现) 因此, 想到抽象统一 Weex 核心解析渲染流程, 通过 C + + 语言实现, 实现 iosandroid 平台核心逻辑统一, 不仅可以增强平台间的一致性, 降低维护成本, 以及扩展平台的成本通过 C+ + 代码执行效率要高于 JAVA, 同时还可提高 Android 端的代码执行性能
提供标准的 Weex Dom API Layer, 简化 DSL 的接入成本, 将大部分 JSFramework native 化;
抽象 Weex 平台无关的核心的处理逻辑, android 和 IOS 的 porting 层尽量做薄, 一方面提高代码的复用率, 另一方面降低新平台的扩展成本;
架构设计上的高可用, 通用的模块可插拔, 例如 JS engine 模块和 Layout engine 模块能低成本地切换;
核心技术模块比如 JS engine 等能标准化输出, 服务更多的业务场景;
来源: https://yq.aliyun.com/articles/444904