Facebook React与Web Components(聚合物)的优缺点


521

相较于即将发布的Web组件规范,Facebook的React有什么主要好处,反之亦然(或者与Google的Polymer库相比,也许更多的苹果之间的比较)?

根据这次JSConf EU演讲和React主页,React的主要好处是:

  • 使用组件模型去耦和增加内聚力
  • 抽象,组成和表现力
  • 虚拟DOM和综合事件(这基本上意味着它们完全重新实现了DOM及其事件系统)
    • 在IE 8上启用现代HTML5事件内容
    • 服务器端渲染
    • 可测性
    • 绑定到SVG,VML和 <canvas>

除了这个虚拟DOM概念(显然)之外,几乎所有提及的内容都是通过Web组件本地集成到浏览器中的。我可以看到虚拟DOM和合成事件在今天对于支持旧的浏览器有何好处,但是不会扔掉大量的本机浏览器代码,而不是像从长远来看那样吗?就现代浏览器而言,这不是很多不必要的开销/重新设计吗?

认为这是React缺少的一些内容,Web组件会为您提供帮助。如果我错了纠正我。

  • 本机浏览器支持(请阅读“保证更快”)
  • 以脚本语言编写脚本,以样式语言编写样式,以标记语言编写标记。
  • 使用Shadow DOM进行样式封装
    • 相反,React具有this,这需要使用JavaScript编写CSS。不漂亮。
  • 双向装订

12
Wrt。双向绑定。此功能在规模上存在问题。在平凡的情况下,它很好用,但是在实际情况下,您通常会发现,要使代码易于管理,您需要绑定一个视图模型,而不是绑定到实际模型,这会使双向绑定的作用远小于最初似乎。我认为它不提供双向绑定可能是React的一个优势,因为它强制使用正确的数据流架构。
Joeri Sebrechts 2014年

8
我看过React,Angular和Knockout。我发现淘汰UI模板,数据和绑定方面是“最干净的”。我想喜欢做出反应,但是尝试创建一个简单的Combobox,我意识到我正在编写更多的代码,并将渲染逻辑与html模板混合在一起。在我看来,这些库/ api正在使我们倒退,而不是前进。关于React的最好的事情是虚拟dom操纵,但是我可以看到,它早早出现在其他已建立的框架中。
mike01010 2015年

41
我很惊讶(也很高兴!)这个问题没有因为“主要基于意见”而被关闭。
iconoclast

4
如果您要进行任何形式的模板制作,则无法编写“脚本语言的脚本”和“标记语言的标记”。Angular,Polymer等使用嵌入HTML的模板DSL。React使用嵌入在JS(JSX)中的模板DSL。在HTML中嵌入DSL的问题是如何建立从JS获取值的范围。这导致了Angular复杂的$ scope系统。另一方面,在JSX中,模板中变量的范围只是JS范围-我发现它不那么令人困惑。
安迪

3
目前,React组件(除非写得不好)会比任何DOM绑定框架中的组件都要快。v-dom和差异魔术是USP的反应。我的意思是-为什么浏览器不会在其本机功能集中建立像这样的差异。是什么阻止了它们,如果什么也没有阻止(阻止它们),那么React的领先优势可能将是短暂的。
fasttrainofthoughts 2015年

Answers:


664

更新: 这个答案似乎很受欢迎,因此我花了一些时间对其进行清理,添加一些新信息并澄清了一些我认为不够清楚的内容。如果您认为其他任何需要澄清或更新的内容,请发表评论。

您的大部分顾虑实际上都是意见和个人喜好问题,但我会尽可能客观地回答:

本机与编译

用普通JavaScript编写JavaScript,用CSS编写CSS,用HTML编写HTML。

过去有很多人在争论是应该 手动编写本机 Assembly还是使用C之类的高级语言来使编译器为您生成Assembly代码。甚至在此之前,人们还是不信任汇编程序,而是更喜欢手工编写本机代码我不是在开玩笑)。

同时,今天有很多人用HamlJade编写HTML ,用SassLess编写CSS 以及使用CoffeeScriptTypeScript编写JavaScript 。在那。有用。有些人喜欢它,有些则不喜欢。

关键是,使用普通JavaScript编写JavaScript,使用CSS编写CSS和不使用HTML编写HTML 根本上没有错误。这实际上是一个偏好问题。

内部与外部DSL

 相反,使用Shadow DOM React进行样式封装则需要使用JavaScript编写CSS。不漂亮。

不管是否,它肯定是表达力。JavaScript是一种非常强大的语言,比CSS(甚至包括任何CSS预处理器)要强大得多。这取决于您是喜欢内部DSL还是外部DSL。同样,优先事项。

(注意:我是在谈论原始问题中引用的React中的内联样式。)

DSL类型-说明

更新:在写完答案后的一段时间里阅读了我的答案,我认为我需要在这里解释我的意思。DSL是一种特定域的语言,它可以是内部的(使用像JavaScript这样的宿主语言的语法-例如,不带JSX的React,或者像上面提到的React中的内联样式),也可以是外部的(使用不同的语法)而不是宿主语言-在此示例中,将JavaScript内联CSS(外部DSL))。

这可能会造成混淆,因为某些文献使用不同于“内部”和“外部”的术语来描述这些类型的DSL。有时使用“嵌入式”代替“内部”,但“嵌入式”一词可能具有不同的含义-例如Lua 被描述为“ Lua:一种可扩展的嵌入式语言”,其中嵌入式与嵌入式(内部)DSL没有任何关系(在在某种意义上说,它是完全相反的-外部DSL),但它意味着它以与SQLite是嵌入式数据库相同的意义被嵌入。甚至在eLua中,“ e”在第三种意义上代表“嵌入式”-这是指嵌入式系统!这就是为什么我不喜欢使用“嵌入式DSL”一词的原因,因为诸如eLua之类的东西可以是从两种不同意义上“嵌入式”的“ DSL”,而根本不是“嵌入式DSL”!

更糟的是,某些项目使混合方案更加混乱。例如。熨斗模板被描述为“无DSL”,而实际上,它只是内部DSL的完美示例,其语法如下:map.where('href').is('/').insert('newurl');

话虽这么说,当我写到“ JavaScript是一种非常强大的语言,比CSS(甚至包括任何CSS预处理器)要强大得多。这取决于您是喜欢内部DSL还是外部DSL。优先事项。” 我在谈论这两种情况:

一:

/** @jsx React.DOM */
var colored = {
  color: myColor
};
React.renderComponent(<div style={colored}>Hello World!</div>, mountNode);

二:

// SASS:
.colored {
  color: $my-color;
}
// HTML:
<div class="colored">Hello World!</div>

第一个示例使用问题中描述的内容:“用JavaScript编写CSS。不漂亮。” 第二个示例使用Sass。虽然我同意使用JavaScript编写CSS可能不是很漂亮(对于“漂亮”的某些定义),但是这样做有一个好处。

我可以在Sass中使用变量和函数,但是它们是按词法作用域还是动态作用域?它们是静态类型还是动态类型?强还是弱?数字类型呢?类型强制?哪些价值观是真实的,哪些价值观是虚假的?我可以使用高阶函数吗?递归?尾声?词汇闭包?是按正常顺序还是适用顺序对它们进行评估?是否有懒惰或渴望的评估?函数的参数是通过值还是通过引用传递?他们易变吗?一成不变?坚持不懈?那对象呢?上课吗 原型?遗产?

这些不是琐碎的问题,但是如果我想了解Sass或Less代码,我必须知道它们的答案。我已经知道了JavaScript的那些答案,因此这意味着我已经在这些级别上理解了每个内部DSL(例如React中的内联样式),因此,如果我使用React,那么我只需要知道这些答案中的一组(以及许多类似的答案) )的问题,而当我用于例如 然后,Sass和Handlebars我必须知道三个答案,并理解它们的含义。

并不是说一种方法总是更好,但是每次您将另一种语言引入混合语言时,您都付出了一些乍一看可能并不明显的代价,而这种代价就是复杂性。

我希望我能澄清一下我的意思。

数据绑定

双向装订

这是一个非常有趣的话题,实际上也是一个优先事项。双向并不总是比单向更好。这是一个有关如何在应用程序中建模可变状态的问题。我一直将双向绑定视为某种有点违背函数式编程原理的想法,但是函数式编程并不是唯一可行的范例,有些人喜欢这种行为,并且两种方法在实践中似乎都很好用。如果您对与React中的状态建模相关的设计决策的细节感兴趣,请观看Pete Hunt的演讲(问题链接)以及Tom Occhino和Jordan Walke的演讲,  他们在本书中对此做了很好的解释。我的意见。

更新:另请参见Pete Hunt的另一篇演讲:可预测,不正确:功能DOM编程

更新2:这是值得注意的是,许多开发商都主张双向数据流或双向绑定,有人甚至称其为反模式。举个例子的助焊剂应用架构,明确避免了MVC模型(这被证明是难以为大型Facebook和Instagram的应用程序),取而代之的是严格的单向数据流(见黑客方式:重新思考Web应用程序开发在Facebook上通过交谈Tom Occhino,Jing Chen和Pete Hunt作了很好的介绍)。另外,对AngularJS的批评也很多 (松散地基于MVC模型的最流行的Web框架,以双向数据绑定而著称)包含针对该双向数据流的参数,请参见:

更新3:另外一个有趣的一篇文章,很好地解释了一些上面disscussed问题被解构ReactJS的流量-不使用MVC与ReactJS通过的Mikael Brassman,作者RefluxJS(单向数据流应用架构熔剂启发一个简单的库)。

更新4: Ember.js当前正在远离双向数据绑定,并且在将来的版本中,默认情况下它将是单向的。参见:灰烬的未来由斯特凡·彭纳从Embergarten研讨会在多伦多叨唠2014年11月15日。

更新5:另请参阅:Ember 2.0 RFC之路-Tom Dale在pull请求中的有趣讨论

“当我们设计原始的模板层时,我们发现使所有数据绑定都是双向的不是很有害:如果不设置双向绑定,那实际上是单向绑定!

从那以后,我们意识到(在React的朋友的帮助下),组件希望能够将数据分发给他们的孩子,而不必警惕任何随意的突变。

此外,组件之间的通信通常最自然地表示为事件或回调。在Ember中这是可能的,但是双向数据绑定的优势常常使人们走上使用双向绑定作为通信渠道的道路。有经验的灰烬开发商不(通常)犯这样的错误,但它是一个容易做。” [强调]

本机与VM

本机浏览器支持(请阅读“保证更快”)

现在终于有了一些无关紧要的问题。

实际上,这里恰恰相反。当然,“本机”代码可以用C ++编写,但是您认为JavaScript引擎是用什么编写的?

实际上,JavaScript引擎在当今使用的优化中确实令人惊叹-这些天不仅是V8,而且SpiderMonkey甚至Chakra都闪闪发光。并且请记住,对于JIT编译器,代码不仅像它本来可能的本机那样原始,而且还存在运行时优化的机会,而这在任何静态编译的代码中都是不可能做到的。

当人们认为JavaScript速度很慢时,通常是指访问DOM的JavaScript。DOM很慢。它是本机的,用C ++编写,但是由于它必须实现的复杂性,它的速度实在太慢了。

打开控制台并输入:

console.dir(document.createElement('div'));

并查看div甚至没有附加到DOM 的空元素必须实现多少个属性。这些只是第一级  属性,即“自身属性”。不是从原型链继承的:

对齐,等待,onvolumechange,ontimeupdate,onsuspend,onsubmit,安装,onshow,onselect,onseeking,onseeked,onscroll,onresize,onreset,onratechange,onprogress,onplaying,onplay,onpause,onmousewheel,onmouseup,onmouseover,onmouseout,onmous onmouseenter,onmousedown,onloadstart,onloadedmetadata,onloadeddata,onload,onkeyup,onkeypress,onkeydown,oninvalid,oninput,onfocus,onerror,oned,onemptied,ondurationchange,ondrop,ondragstart,ondragover,ondragleave,ondragenter,ondrague,onclickd, oncontextmenu,onclose,onclick,onchange,oncanplaythrough,oncanplay,oncancel,onblur,onabort,spellcheck,isContentEditable,contentEditable,outerText,innerText,accessKey,隐藏,webkitdropzone,draggable,tabIndex,dir,translate,lang,title,childElementCount,lastElementChild,firstElementChild,子项,nextElementSibling,previousElementSibling,onwheel,onwebkitfullscreenerror,onwebkitfullscreenchange,onselectstart,onsearch,onpaste,oncut,oncopy,onbeforepaste,onbeforecut,onbeforecopy,webkitShadowRoot,数据集,classList,className,outerHTML,innerHTML,scrollHeight,scrollLeft,scrollLeft clientHeight,clientWidth,clientTop,clientLeft,offsetParent,offsetHeight,offsetWidth,offsetTop,offsetLeft,localName,prefix,namespaceURI,id,样式,属性,tagName,parentElement,textContent,baseURI,ownerDocument,nextSibling,previousSibling,lastChild,firstChild,firstChild,childNodes, parentNode,nodeType,nodeValue,nodeNameoncopy,onbeforepaste,onbeforecut,onbeforecopy,webkitShadowRoot,数据集,classList,className,outerHTML,innerHTML,scrollHeight,scrollWidth,scrollTop,scrollLeft,clientHeight,clientWidth,clientTop,clientLeft,offsetParent,offsetParent,offsetHeight,offsetWidth,offsetTop,offsetLeft,localName,prefix, namespaceURI,id,样式,属性,tagName,parentElement,textContent,baseURI,ownerDocument,nextSibling,previousSibling,lastChild,firstChild,childNodes,parentNode,nodeType,nodeValue,nodeNameoncopy,onbeforepaste,onbeforecut,onbeforecopy,webkitShadowRoot,数据集,classList,className,outerHTML,innerHTML,scrollHeight,scrollWidth,scrollTop,scrollLeft,clientHeight,clientWidth,clientTop,clientLeft,offsetParent,offsetParent,offsetHeight,offsetWidth,offsetTop,offsetLeft,localName,prefix, namespaceURI,id,样式,属性,tagName,parentElement,textContent,baseURI,ownerDocument,nextSibling,previousSibling,lastChild,firstChild,childNodes,parentNode,nodeType,nodeValue,nodeNameparentElement,textContent,baseURI,ownerDocument,nextSibling,previousSibling,lastChild,firstChild,childNodes,parentNode,nodeType,nodeValue,nodeNameparentElement,textContent,baseURI,ownerDocument,nextSibling,previousSibling,lastChild,firstChild,childNodes,parentNode,nodeType,nodeValue,nodeName

其中许多实际上是嵌套对象-要div在浏览器中查看空本机的第二级(自己)属性,请参阅此小提琴

我是说认真的,每个div节点上都有onvolumechange属性吗?错了吗 不,这只是事件处理程序之一的旧式DOM Level 0传统事件模型版本,“ 必须所有HTML元素支持,内容属性和IDL属性都应支持” [强调] HTML规范第6.1.6.2节由W3C-没办法解决。

同时,这些是divReact中伪DOM的第一级属性:

道具,_owner,_lifeCycleState,_pendingProps,_pendingCallbacks,_pendingOwner

完全不同,不是吗?实际上,这是将整个对象序列化为JSON(LIVE DEMO)的原因,因为您实际上可以  将其序列化为JSON,因为它不包含任何循环引用-在本机DOM领域中这是不可想象的(它只会抛出异常)):

{
  "props": {},
  "_owner": null,
  "_lifeCycleState": "UNMOUNTED",
  "_pendingProps": null,
  "_pendingCallbacks": null,
  "_pendingOwner": null
}

这几乎是React可以比本机浏览器DOM更快的主要原因-因为它不必实现这种混乱

请参阅Steven Luscher的演示文稿,以了解更快的方法:用C ++编写的本机DOM或完全用JavaScript编写的伪DOM。这是一个非常公平和有趣的演示。

更新: 未来版本中的Ember.js将使用受React启发的虚拟DOM来提高性能。参见:灰烬的未来由斯特凡·彭纳从Embergarten研讨会在多伦多叨唠2014年11月15日。

概括起来:Web组件中的功能(例如模板,数据绑定或自定义元素)将比React具有很多优势,但是直到文档对象模型本身被大大简化之后,性能才不是其中之一。

更新资料

我发布此答案两个月后,这里有一些相关新闻。正如我刚刚在Twitter上所写的那样,尽管Wikipedia称 “ Atom基于Chromium并用C ++编写”,但GitHub用JavaScript编写的GitHub 最新版本的Atom文本编辑器仍使用Facebook的React获得更好的性能。本机C ++ DOM实现(请参阅《原子核》 由于它附带了自己的Web浏览器,因此可以保证对Web组件的支持。这只是一个现实世界项目的最新示例,该项目可以使用Web应用程序通常无法使用的任何其他类型的优化,但是即使Atom仍选择使用本身用JavaScript编写的React来实现最佳性能。并不是一开始就使用React构建的,因此这样做并不是一件小事。

更新2

由托德·帕克一个有趣的对比使用WebPagetest比较的性能TodoMVC写成角,骨干的例子,灰烬,聚合物,CanJS,YUI,淘汰赛,反应,鞋带。这是我到目前为止看到的最客观的比较。这里重要的是,所有各个示例都是由所有这些框架的专家编写的,它们都可以在GitHub上获得,并且可以认为认为某些代码可以进行优化以提高运行速度的人可以对其进行改进。

更新3

未来版本中的Ember.js将包含此处讨论的许多React功能(包括虚拟DOM和单向数据绑定,仅举几例),这意味着起源于React的想法已经迁移到其他框架中。请参阅:通往Ember 2.0的RFC之路-Tom Dale(开始日期:2014-12-03)的拉取请求中的有趣讨论:“在Ember 2.0中,我们将采用“虚拟DOM”和数据流模型,其中包括来自React的最佳创意,并简化了组件之间的通信。”

同样,Angular.js 2.0也实现了此处讨论的许多概念。

更新4

我必须详细说明几个问题才能回答Igwe Kalu的评论:

“当React最终简化为普通JavaScript时,将React(JSX或编译输出)与普通JavaScript进行比较是不明智的。[...]可以将React用于DOM插入的任何策略应用于不使用React的情况。在考虑相关功能时,除了方便性之外,没有增加任何特殊的好处。” (完整评论在这里

如果还不够清楚,我会在部分答案中比较直接在本机DOM(在浏览器中作为宿主对象实现)和React的假/虚拟DOM(在JavaScript中实现)上运行的性能。我要说明的一点是,用JavaScript实现的虚拟DOM 可以胜过用C ++实现的真实DOM,而不是 React不能胜过JavaScript(这显然是没有用的,因为它用JavaScript编写的)。我的观点是,并不总是保证“本机” C ++代码比“非本机” JavaScript更快。用React来说明这一点只是一个例子。

但这句话引起了一个有趣的问题。从某种意义上说,您确实出于任何原因(例如性能,可移植性,功能)均不需要任何框架(React,Angular或jQuery),因为您始终可以重新创建框架为您所做的工作并重新发明轮子-如果您可以证明成本合理。

但是-戴维·史密斯很好地把它放在如何比较Web框架的性能时,错过了这一点:“当比较两个web框架,这个问题是不是可以我的应用程序快速与框架X.的问题是我的应用程序框架,快速X。”

我2011年的回答中:不使用jQuery的一些经验性技术原因是我解释了一个类似的问题,即没有jQuery之类的库就不可能编写可移植的DOM操作代码,但是人们很少这样做。

当使用编程语言,库或框架时,人们倾向于使用最方便或惯用的做事方式,而不是完美但不便的方式。好的框架的真正价值在于使原本很难做到的事情变得容易-秘诀就是使正确的事情变得方便。结果仍然具有与最简单的lambda演算形式或最原始的Turing机器一样完全相同的功能,但是某些概念的相对表现力意味着这些概念往往更容易或根本不易于表达。正确的解决方案不仅可行,而且已广泛实施。

更新5

反应+性能=?保罗·刘易斯(Paul Lewis)在2015年7月发表的一篇文章中展示了一个示例,其中针对无限数量的Flickr图片列表,React比手工编写的普通JavaScript慢,这在移动设备上尤其重要。此示例表明,每个人都应始终测试特定用例以及特定目标平台和设备的性能。

感谢凯文Lozandier它带给我的注意


75
这就是我所说的全面答案,谢谢!
Demwunz 2014年

14
看起来Atom正在远离React。见github.com/atom/atom/issues/3677
JuhoVepsäläinen2014年

6
@ash:如果您进一步阅读该线程,他们会谈论他们最终希望如何完全脱离React和其他框架,并使用自定义元素和影子DOM滚动自己的框架。
musicfreak 2014年

3
只是为了澄清上面的措辞,在@ErikAllik的列表中,FRP(功能性反应式编程)不是一种新语言,而是一种越来越流行的方法。事实上,“榆树是基于功能性反应式编程的想法”(从elm-lang.org),和他提到,有Haskell的,等玻璃钢框架
乔恩·库姆斯

5
tl;仍然阅读-精彩,详细的答案!
Mark K Cowan

16

聚合物很棒。React很棒。它们不是同一件事。

Polymer是用于构建向后兼容的Web组件的

React是MVC中的V。这是View,仅此而已。至少不是一个人。

React不是框架。

React + Flux + Node +(Gulp或Grunt)与框架更具可比性,但是其中3个根本不是React的一部分。

有许多技术,模式和体系结构样式可以响应开发人员,但响应本身不是框架。

令人遗憾的是,没有人花时间说出最简单的事情,即不应将它们进行比较。它们有一些重叠,但是彼此之间的差异更大。

它们都允许您以不同的方式定义Web组件。除此之外,它们是非常不同的工具。


因为它保存并更新数据状态并通过组件呈现html片段,所以React不是M和V,不仅是V吗?
abelito

1
有诸如flux或redux之类的反应状态管理库,但它们并未与react打包在一起。
Robotsushi

哦,我明白了,在将视图数据提交到服务器端之前,我们不认为它是模型数据。即使React拥有组件状态(视图数据),在提交之前,它仍然是视图数据。那讲得通。
abelito

15

React专家对React和Web组件之间的比较有很好的解释

试图将React与WebComponents进行比较和对比不可避免地会得出错误的结论,因为这两个库是为解决不同的问题而构建的。WebComponents为可重用的组件提供了强大的封装,而React提供了一个声明式库,该库使DOM与数据保持同步。这两个目标是相辅相成的。工程师可以混合和匹配这些技术。作为开发人员,您可以自由地在WebComponents中使用React,或在React中使用WebComponents,或两者都有。


14

具体来说,另一个答案是:

用普通JavaScript编写JavaScript,用CSS编写CSS,用HTML编写HTML。

没有什么可以阻止您使用CoffeeScript,TypeScript,ClojureScript或其他任何语言编写Javascript。这纯粹是一个偏好问题。

HTML是用于静态 HTML文档的最佳DSL 。但是它不提供动态HTML。在浏览器中,使HTML动态化的最佳语言是Javascript,而不是具有特定Javascript DOM操作的纯HTML或像Handlebars这样的模板语言,它们甚至都不是半语言。

对于CSS,如果CSS是静态的,则照常编写。如果需要基于某些运行时值来动态化,则它与HTML的故事相同:Javascript是使其动态化的最佳方法。


1
我很欣赏这个答案,但这实际上不是我的意思。希望我的编辑可以使问题更清楚一些?
CletusW 2014年

1
抱歉,事实并非如此。您仍然可以在任何单独的文件中以任何样式语言编写样式。React的JSX使其看起来像您在使用标记语言。
DjebbZ 2014年

3
“ Javascript是使[CSS]动态化的最佳方法”-简单地说,它实际上并不能解释原因。
pilau 2014年

1
好吧,如果样式/类需要根据用户输入或业务规则进行更改,只需使用javascript进行更改即可。在普通js中,您将操作DOM节点的classList或styles属性。使用React,您可以实现操作虚拟DOM的相同目标。比较清楚吗?
DjebbZ 2014年

2
React的核心贡献者Vjeux最近发表了演讲,讨论了如何使用React推动“ CSS in JS”的概念。我认为这很有趣,您可能愿意看看它的含义
DjebbZ 2014年

6

我没有使用过Web组件,但是看起来它们要求您向事件处理程序中添加手动编码的变异逻辑。

来自Polymer示例的代码段:

 <script>
   Polymer({
     counterChanged: function() {
       this.$.counterVal.classList.add('highlight');
     },
 ...

React的全部目的是通过消除变异逻辑来降低复杂性。相反,您可以天真地重新生成虚拟DOM,然后让React的diff算法找出实际DOM中需要更改的内容。


5
不知道您在哪里找到该示例,但是Polymer也不鼓励手动DOM更改以支持数据绑定(包括类名)
CletusW 2014年

这是来自polymer-project.org主页上“创建元素”选项卡的示例。
limscoder 2014年

4
哇,你是对的!我想他们只是想要一个自动寻找节点的例子。不过,那可能不是最好的选择。
CletusW

6

我认为React的最大缺点是它不是基于Web标准的。目前,React是一个非常强大的工具,但是由于它会尽可能绕开浏览器提供的功能,因此随着浏览器内置功能的不断发展,现在看来有意义的决定可能在几年后就不再有意义。提高。因此,我想谈一谈它以及它如何影响Web应用程序的几个不同方面。

性能

人们喜欢争辩说,React的优势在于它完全重新发明了整个DOM和事件模型,而现有的标准DOM既繁琐又昂贵,什么都不是,但是到最后,我还没有发现做出比我编写完善的Backbone或Polymer应用程序更好的反应。实际上,根据我的大多数专业经验,React的性能实际上要差一些。这并不是说React速度很慢...这并不是我们都认为这是在我们开始使用它之前的前沿性能选择。

在RSP的回答,他指出,作出反应的DOM模型一个div是多少重量更轻比原生的DOM DIV,这是千真万确的。但是,为了使React有用,该“虚拟” div必须在某个时候最终成为真正的div。因此,在我的世界视野中,这不是React div与本机div的问题。这是一个React div +一个本机div与一个本机div。React的DOM版本的开销是不平凡的,并且如果标准曾经丢弃了一些不需要的属性并允许本机DOM节点更轻巧,那么开销似乎真的很昂贵。

在我以前的工作场所之一,我们在Polymer中有一些应用程序,在React中有一些应用程序。最终,其中一个早期的Polymer应用程序最终被用React重写,因为这是该公司的标准,并且基于测量,我得出了同一应用程序的React版本比使用Polymer版本多了30%的内存。 ,尽管差异很小,但是Polymer版本的渲染时间也更少。这里要考虑的一件事是,我们谈论的是人们编写的应用程序,而人们并不完美,因此该应用程序的React实现有可能没有利用React的全部功能。但是我认为至少其中一部分与React是拥有自己的DOM版本所产生的开销有关。

React使用自己的模型重新发明了整个DOM,然后将其用于主要的性能优化。视图被渲染到虚拟DOM中,并且被投影到真实DOM中。发生更改并且必须更新视图时,视图会再次重新重新渲染到虚拟DOM中,并且该树与前一棵树进行了比较,以确定必须在实际DOM中更改哪些节点才能反映此更改。在视图中。尽管这是进行有效DOM更新的非常聪明的方法,但是维护所有这些虚拟DOM树并进行比较以确定实际DOM中的更改时,存在开销。目前,这种性能开销已大大抵消了这些开销,但是随着本机DOM随着时间的推移得到改进,规模将朝另一个方向转移。我担心React应用可能会老化,并且如果在3年内,它们将比直接处理DOM的速度慢得多。这种虚拟DOM方法有点像大锤子,其他类似Polymer的库也已经能够实现非常有效的方法,以更微妙的方式处理DOM。

性能更新: 我前一段时间偶然发现的库之一,可以更好地管理DOM更新。它是Google的增量Dom库,我认为它可以与dom就地一起使用并且不必创建“虚拟副本”,这是一种更干净的方法,而内存开销却少得多。在此处查看更多信息:http : //google.github.io/incremental-dom/#about

声明性组件与命令性组件

在谈论将应用程序组件化时,您经常听到的一件事就是组件具有声明性的所有优点。在React的世界观中,一切都很好并且具有声明性。您编写了返回标记的JavaScript,React将所有标记都粘合在一起。如果您要处理一个仅使用React而不使用其他任何东西的全新应用程序,那就太好了。您可以编写一些组件,只要您在React拥有的DOM片段中,就很简单,只需将该标签放在页面上即可使用您的组件。

但是,一旦您开始使用这些组件并在React之外使用它们,事情就会变得更加混乱。因为将React组件制作为标签的方式完全超出了Web标准提供的内容,所以React就是什么都不知道如何为您提供声明性的方式来使用这些组件。如果我想将React组件放入使用Handlebars模板的现有Backbone视图中,则必须在模板中使用可以用作句柄的类或ID渲染虚拟div,然后编写命令式JavaScript来查找该虚拟div并进行安装您的组件。获得了使用服务器端模板的Express.js应用程序?嗯,就是同样的歌舞。一个JSP页面?你笑了,但是仍然有大量的应用程序在使用它们。除非您是没有现有代码的启动公司,否则您将 不得不编写一些管道以便在许多应用程序中重用您的React组件。同时,Polymer通过Web组件标准来实现组件,并且通过使用“自定义元素”规范,Polymer能够创作浏览器本身知道如何使用的组件。我甚至可以在React组件内部将Polymer组件放入JSP页面,Express.js模板,ASP.NET视图,Backbone视图...。在任何可以使用HTML的地方,都可以使用Polymer组件。进行重用工程的人们正在寻求Web标准,因为标准是使彼此容易兼容的契约。YouTube不断在Polymer中创作越来越多的作品(来源:Polymer通过Web组件标准来实现组件,并且通过使用“自定义元素”规范,Polymer能够创作浏览器本身知道如何使用的组件。我甚至可以在React组件内部将Polymer组件放入JSP页面,Express.js模板,ASP.NET视图,Backbone视图...。在任何可以使用HTML的地方,都可以使用Polymer组件。进行重用工程的人们正在寻求Web标准,因为标准是使彼此容易兼容的契约。YouTube不断在Polymer中创作越来越多的作品(来源:Polymer通过Web组件标准来实现组件,并且通过使用“自定义元素”规范,Polymer能够创作浏览器本身知道如何使用的组件。我甚至可以在React组件内部将Polymer组件放入JSP页面,Express.js模板,ASP.NET视图,Backbone视图...。在任何可以使用HTML的地方,都可以使用Polymer组件。进行重用工程的人们正在寻求Web标准,因为标准是使彼此容易兼容的契约。YouTube不断在Polymer中创作越来越多的作品(来源:我甚至可以在React组件内部将Polymer组件放入JSP页面,Express.js模板,ASP.NET视图,Backbone视图...。在任何可以使用HTML的地方,都可以使用Polymer组件。进行重用工程的人们正在寻求Web标准,因为标准是使彼此容易兼容的契约。YouTube不断在Polymer中创作越来越多的作品(来源:我甚至可以在React组件内部将Polymer组件放入JSP页面,Express.js模板,ASP.NET视图,Backbone视图...。在任何可以使用HTML的地方,都可以使用Polymer组件。进行重用工程的人们正在寻求Web标准,因为标准是使彼此容易兼容的契约。YouTube不断在Polymer中创作越来越多的作品(来源:http://react-etc.net/entry/youtube-is-being-rebuilt-on-web-components-and-polymer),而我只能想象Polymer的基于标准的方面就是原因。可以将位于YouTube页面中间的YouTube播放器变成一个将内容源作为属性的组件,突然之间,任何想要将YouTube播放器嵌入其页面的人都可以使用YouTube使用的完全相同的播放器代码,他们只需在页面上粘贴标签即可。

摘要

我可以看到,React肯定有一些吸引人的方面。如果您使用的只是React,则可以构建一些小部件和某些组件,并声明式地在各处重复使用它们。但是我认为,如果React使用某些Web组件标准来实现其功能,而不是关闭并在浏览器中构建浏览器以及使所有内容保持同步的复杂机制,它的状况就会好得多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.