专栏首页携程技术干货 | Qreact,去哪儿网的迷你react方案

干货 | Qreact,去哪儿网的迷你react方案

作者简介

钟钦成,网名司徒正美,著名的JavaScript专家,去哪儿网前端架构师。在GITHUB拥有复数个著名的轮子,著有《javascript框架设计》一书。本文来自司徒正美在“携程技术沙龙——新一代前端技术实践”上的分享。

*视频由“IT大咖说”提供,时长约45分钟,请在WiFi环境下观看*

去哪儿网在React Native深耕多年,对React内部实现的了解在国内应该是非常领先的。迫于项目对React体积的极致需求,我们推出了自己的迷你化方案——Qreact。

Qreact比市面上的其他迷你react框架的实用性更强,基本上可以说无缝切换到任何已有的react 15工程中,能极大地改善对体积的压力,这在对流量非常苛刻的移动端上尤其重要!

我们从今年1月份快速启动项目,在1个月内大致完成了功能,Demo,并配合现有的复杂例子进行验收。本文将分享我们在做这轮子过程中的一些想法,包括竞品分析,实现思路,项目风险控制等等。

一、核心需求

我们并不是无事找事,为造轮子而造轮子。虽然有KPI的成分,但它的核心需求是来自业务线,可以说就算我们不造,公司内部其他人也会造一个,但那个质量可能无法保证,毕竟公司绝大部分的高手都分配到我们事业部。

由于没有产品经理,我们需要充当产品经理的角色,聆听业务线的需求,自己挖掘需求。

去哪儿深耕React多年,构建了两个基于React的UI库,它们都是用于移动端。如果这些库都是内置在APP中,应该没有要求。但是去哪儿分成十来个事业部,根据事业部的赚钱能力分配更新包的体积。为了能让用户在wifi上更新我们的APP,更新包的体积一般不超过100MB,因此像这样公用的框架与库体积越少越好。

此外,其中一个UI库是用于手机浏览器上,我们称之为React Web,用户每次打开我们的页面,都会加载一遍React与相关组件,这个对体积就更加敏感。因此当我们完成React Web,就着眼于迷你React的开发。

这个新的框架有三个核心需求:

1、体积小。移动端对体积一向敏感,因此在jQuery时代,zepto能割踞一方。

2、支持事件系统,这不是简单add Event Listener,是React原来的那套Synthetic Event。它帮我们搞定300ms延迟,还有滚动列表时误触发点击的问题。如果你不用它,你需要让业务线参照iscroll的原理自造一个。

3、能直接替换。换言之,新框架与原框架的功能几乎一致。因此许多业务已经

用React开发完毕,不希望做太多改动。由于业务线有时时间赶,碰到难题搞不定,会倾向用一些怪招歪招。在无法预料对方用什么API的情况,新框架框架覆盖原React的各种偏门用法。

下面是一个紧急修复的补丁:

图1

我们列举一下各种偏门的API与用法

1、mixin包含mixin。这个在RN很常见。

2、ref, setState传函数的用法

3、context与getChildContext的运用,虽然官方明确不建议大家用,但是著名的react-redux在源码里用到了。

4、_rootNodeID, _hostParent,_hostNode这些内部属性用在后端渲染与事件系统中。

二、竞品分析

图2

在立项后,我们开始找市场上的同类产品,如果有满足的,我们就不用开发了。目前,前端要找这些框架,只有一个去处,就是GITHUB。这是开源界的宝库,应有尽有,琳琅满目。

由于代码公开,大家可以抄抄,因此每流行一样的东西,大家都是一窝蜂上的。除开那些纯练手的项目,每个库都有自己独到之处。

自从React推出虚拟DOM来解决复杂应用的性能问题以来,GITHUB上有上百个虚拟DOM的库,包括之前的angular, vue2都在底层使用这种性能利器。

图3

这是一些虚拟DOM框架或库的数据,从相似度,性能,流行度,版本更新等情况综合考虑,我们也只能选上面三者:inferno, preact, react-lite。

inferno从各方面来看,是无可挑剔的,性能比排行第二的kivi快20倍,更不用说vue,angular什么之流。每个库都会吹自己的框架有多快,但inferno的主页上有大量测试页面,是有真实数据支撑的。但是它偏面追求性能,源码里的可读性太差。看不懂,无从入手,只能遗憾地放弃了。

其他性能流有citijs, snabbdom, virtual-dom。最早搞出性能引擎的是citijs,然后基于它上面分化出kivi, ivi, snabbdom,然后vue2.0又直接将snabbdom库整合到它里面。virtual-dom则是走另一种性能优化方式。但它们都是迷你库,API与React差太远。

于是只剩下preact与react-lite。

三、设计思路

由于是业务线的迫切需求,并且拖得越久,就越多项目用上RN,到时需要回归测试的项目就越多,因此必须尽快搞出来。我们就不打算重造轮子,而是在已有轮子上改改。

第一版是基于react-lite。这是因为react-lite是携程的工业聚大神写的,携程是我们的兄弟公司,应该比较好交流。但现实中发现,这个库的扩展性不足,比如说事件系统那里,需要传入4个参数,在react-lite里只能拿到三个参数,想尽方法也无法凑齐第四参数。还有一些内部属性,渲染流程与原装React差得太远了。在双方折腾了2个星期后,我们组有人心灰意冷,着手后备方案,preact。

preact比起react-lite多出几个优势:

1、官方提供兼容补丁preact-compat

2、插件巨多

3、ISSUR活跃,当天提问题,大概到晚上,外国人起床就有回应了。

4、扩展方便

尤其第4点,在开发qreact时,我们都为双方提了不少ISSUE。其实程序员还是比较腼腆,不愿麻烦人,因此我们写框架时还是多留一些扩展接口吧。

整个qreact的架构大概就是:

qreact= preact改+preact-compat改+react-web事件系统迷你版

在preact的源码里一个叫options.js的文件,里面有一个options的对象,它会被框架的多个关键方法调用。我们通过为它重新实现某些方法,就达到改写框架的目标。

https://github.com/developit/preact/blob/master/src/options.js

图4

两个react-lite的难点问题,由于options的扩展机制太灵活了,一下子被摆平。

1、事件系统需要传入4个参数的问题。在options添加一个handle Event方法。

2、内置属性问题,在options重写vnode方法。

重点说一下内部属性问题:

图5

随着版本的升级,这些内部属性越来越多,这里讲解一下其中三个:

图6

这了让preact支持它们,我们是在框架diff节点时,重新添加上它们的。因为这时,我们能轻松知道一个节点在DOM树的上下关系。

最后是对事件系统进行瘦身。React有16000行,其中10000行都是事件系统相关的。再加上React Native中的Pan Responder系统。这体积非常庞大。但是如果我们将要支持的浏览器收窄一点,不支持IE系列与firefox系列。起码在事件对象的构造器上,我们可以做一些合并操作。

下面React中的事件构造器列表:

https://github.com/facebook/react/tree/v15.3.2/src/renderers/dom/client/syntheticEvents

它们浓缩成一个事件构造器后,代码少了3000行。

我们再对事件插件进行围剿。因为我们不需要mouseenter, mouseleave, input, composition,beforeinput的兼容,又可以减少许多行。

https://github.com/facebook/react/tree/v15.3.2/src/renderers/dom/client/eventPlugins

最后成果是 qreact缩少到6000行,事件系统占其中的4000行,min后的体积为39kb。原版React的min体积是140kb。减少近80kb。

体积算是达标了,那么性能如何呢?毕竟我们使用React的初衷是因为它的性能太好了。React的性能主要来自它的虚拟DOM的diff算法。体积缩水了,它的diff算法肯定也打折扣。这时preact提出两个后备方案:

1、减少要比较的虚拟DOM的数量 hydrate。这是发端于inferno的优化方案,通过合并相邻的字符串或数字,减少虚拟DOM数量。

图7

2、减少要生成的真实DOM的数据recycle。上面的hycycle也会减少真实DOM的数量,但我们还可以将要移除的真实DOM保存起来,重复利用这些真实DOM。

通过这两种机制,大大弥补qreact diff算法的缺憾。此外,我们还可以通过动静分离的方式来提高性能。在定义JSX时,我们就能得知某个元素是否包含花括号,有花括号说明其是动态的,反之是静态的,但一个元素与其所有子孙都没有花括号,那么这个子树可以整体缓存起来,以后转换为真实DOM后,它能缓存起来。

然后在组件的render方法中,对于这部分的React Element每次返回相同的对象,并且在上面添加一个标记,碰到两个对象都有这个标记,就直接返回,不往下比较了。这是inferno提出的另一个性能优化方案。

最后验证性能是用ListView进行测试的,和原来一样流畅。

四、分享展示

里面最重要的两个例子就是yo-demo与qunar-react-native-web

本文分享自微信公众号 - 携程技术中心(ctriptech),作者:司徒正美

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-03-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 干货 | React Native实践之携程Moles框架

    因为支持用javascript开发原生应用,React Native一推出就受到不少公司热捧,各家都跃跃欲试。但有一个痛点是,在移动端,我们是否有必要开发多套程...

    携程技术
  • RN沙龙 | 那些携程火车票业务在RN实践中踩过的坑

    姚瑞琼,前端程序媛一枚。2014年毕业后加入携程火车票事业部,今年年初起至今,主要负责React Native方案在火车票业务线的实践,先后参与并负责汽车票RN...

    携程技术
  • 干货 | React Fiber 初探

    携程技术
  • GitHub上最流行的Top 10 JavaScript项目

    统计出Github中所有项目的数量,几乎是不可能的,而明确指出哪些是最优秀的项目就更不可能了。如果说到JavaScript,曾经极富创新的项目(很可能)在一两个...

    业余草
  • 高质量前端资源 ( 一 )

    日常喜欢浏览各种技术网站包 hashnode ,stepoint, medium , hacknews , stackoverflow , github ,国内...

    陈远峰
  • 【前端必看】2017 年 JavaScript 全面崛起大运势

    最受欢迎项目 ? 下面是年度最流行的项目,不区分类别。 Vue.js蝉联冠军 Vue.js 再次强势登顶年度排行榜冠军,今年在 GitHub 上新增了超过 40...

    IT派
  • 不能因为你没有新产出,就意味着你没有提供价值

    文章是好文章,能一窥大厂顶级开源项目团队的日常。细读后发现,从文章隐隐透露出作者:

    公众号@魔术师卡颂
  • 愿自己活成自己喜欢的样子

    三十而立的姑娘,虽没有经历过太多的波涛海浪,却也经历过几次的悲欢离合; 每次的完美邂逅,从无话不说到无话可说,似乎也没有那么漫长。 遇到你之前,我一个人睡觉,一...

    用户2196435
  • 【拓展】655- React 与前端开发的那些年

    这几天在通过各种资料,了解了 React 「出现的背景」,还有「前端发展的那些年」,不得不说,感觉真的神奇!~

    pingan8787
  • 为什么使用React作为云平台的前端框架(PPT)

    大家好,很高兴可以和大家分享“为什么使用React作为我们的前端框架”。 首先,我们来看一下普元云的总体架构图。 ? 从图中可以看到,在我们普元云平台中,我们最...

    yuanyi928

扫码关注云+社区

领取腾讯云代金券