返回 登录
0

# 代码约架?Vue.js和Binding.scala两大框架作者的PK

作为一个知乎小透明,最近看了一场炸鱼大片。两天前,民工叔因为 Teambition 是 React 技术栈而离职 一文,引发了激烈的讨论。其中民工叔偏向的技术选型Vue.js的作者出没现场黑了一把Angular2,其它各吃瓜群众表示还没反应过来该如何站队之时,Binding.scala的作者则跳了出来顺带把Vue.js、ReactJS、AngularJS、ELM、diode黑了个遍。各人语言犀利,毫不留情。

前端框架的开发,js在各大厂小店都是第一顺位的选择,然而在这样的气氛中,为啥突然出现了Scala这么一股泥石流呢?

在这么一个小小的角落里,一场大戏在开演,吃瓜群众表示看得很过瘾,所以顺了顺过程,技术博客处女作就这样交出去了

这里节录一下其中几个比较正面的交锋,及参与者。

杨博,Binding.scala作者,简称杨
尤雨溪,Vue.js的作者,简称尤
贺师俊, 犀利的技术批评者,前端技术资深专家,简称贺

杨称,用Binding.scala写的程序所需代码行数不到ReactJS的三分之一,甚至比以简洁著称的Vue.js还要短。

尤还以颜色,用Vue.js重新写了一个135行的TodoMVC新版本,比Binding.scala还短。

杨随后贴出了122行的Binding.scala版TodoMVC。

尤没有跟进更短的版本,但他指出122行的Binding.scala版TodoMVC,要比Vue.js字符数多30%。

杨认为Vue.js字符数少的代价是API更臃肿。Vue.js 90%的API,在Binding.scala用一个函数就可以全部代替。

在前端技术大爆炸的今天,大家怎么看待这场代码PK呢?这一场炸鱼,对各厂的前端选型有木有带来一丝波动?

以下是部分的讨论记录,有点长。按时间顺序,也可直接点击知乎链接参观

已经用惯 react 的人不愿意换栈可以理解,但是居然折衷到 ng2 去了,这我也是有点醉。。。这跨度比 react 到 vue 还大得多得多啊。

Vue.js, ReactJS, AngularJS各有各的坑,所以你们争执不下也很正常。

如果你们试过Binding.scala大家就不用争吵了嘛。

你看,世界人民纷纷弃用AngularJS、ReactJS、ELM、diode,改投Binding.scala:

如何看待reactive web框架Binding.scala ?

贺 -> 杨

做比较得有成本的。你觉得你的东西好,可以写一些对比然后给大家看。但是要求别人自己先去看就强人所难了。更不要暗示别人“不懂”,“信口开河”。这对推广你的东西并没有好处。

杨 -> 贺

贺老师您说得对,这是我写的对比:
* More than React(一)为什么ReactJS不适合复杂交互的前端项目?
* More than React(二)组件对复用性有害?
* More than React(三)虚拟DOM已死?
* More than React(四)HTML也可以静态编译?

希望您看完后给我一些反馈

贺 -> 杨

我先简单给你讲一下大的方面,bindings.scala因为整个技术栈是基于scala的,本身你就不能指望能说动react/vue/ng的人转向它。你看这几个技术栈都是基于js的,转换都要争论,何况迁移到非js生态?如果有人要选非js,他甚至优先选elm,也不见得是scala。因为elm之于js就类似scala之于java,也就是亲缘更近。也正是因为更大的技术生态的区分,你讲的sbt配置比webpack之类的更简单,其实并没有什么卵用,因为没有人会因为配置这点次要的问题就转换整个技术栈。所以你在推广的时候的诉求本身就有问题。bindings.scala能够做到最好的成果就是成为scala社区的第一web框架,如果你能像elm一样反哺js生态下的重要框架,就可以说逆天了。再其他的,只能是不切实际的奢求。没办法,这是历史进程决定的,不是个人努力可以改变的。

贺 -> 杨

再给你说下这系列文章。第一个是,你讲的react的一些缺点,是有,但是是不是那么大?不见得。而且社区自己可能已经有其他方案,比如vdom的实现就数不清了。第二个是,“组件对复用性有害”这就是个标题党,我不是说组件的方式就一定好,实际上我自己确实对组件(自定义标签)是有一定保留的,但你根本没讲清楚到底有害在哪里,而且react也完全可以按照不用组件的方式写个大render。注意,react/vue/ng/polymer甚至webcomponents标准都引入组件(自定义标签),难道他们都是傻叉?至少你现在的文章完全没有说服力,最后大部分人只能反过来认为bindings.scala缺少组件特性,而不会认为这是你的优点。第三个,就算你的精确绑定啊,html语法支持都是优点,vue技术栈已经都具备了。总之,仅按照你这系列文章连我这个对react有所保留的人也说服不了。

杨 -> 贺

第一个,ReactJS的那些缺点大不大要看跟谁比,如果跟AngularJS1相比,确实缺点不大,毕竟Angular1更臃肿不是?但要跟Binding.scala比,这些缺点大概比Binding.scala难用3倍以上。我在More than React 系列文章中的各个例子,每个ReactJS实现都超过Binding.scala的3倍代码行数。

虚拟DOM这个算法,过去,还是挺有用的。现在,有了精确数据绑定的算法,无论是性能还是易用性都压制了虚拟DOM,再谈“虚拟DOM的实现数不清”这就有点井底之蛙的感觉了。

我觉得贺老师,您其实可以跳出井外看看,外面的世界很大的。

杨 -> 贺

第二个,具体在More than React(二)组件对复用性有害?中,ReactJS 例子中三分之二的代码都是多余的,是 Component 带来的语法噪音。

首先您得先看代码,承认一个客观事实,Binding.scala要比ReactJS简单得多。有了这个客观事实之后你在去找原因,那么您就会发现ReactJS复杂的原因之一是React.Component的语法噪音。

如果您认为我写的文章是在“论证”React.Component不好,那就变成语言圣战了,谁也说服不了谁。

贺老师您读一下代码,先承认事实,然后再体会一下。

杨 -> 贺

第三个,我写文章的目的可能不是为了说服贺老师。我也不指望贺老师看完文章,毕竟我连说服贺老师把Binding.scala的名字拼对都做不到。

贺 -> 杨

Component绝不可以用语法噪音来批评。因为它提供了额外的抽象机制。你如果要论证Component不好,你得论证这种抽象不好或者没用。明白了没?

贺 -> 杨

比较代码行数虽然很直接,但是其实没什么卵用。你要相信一点,在没有特别巨大的抽象方式的改进时,做同样的事情,代码是不会有非常大的差异的。这是信息论决定的。你最多去掉一些语法冗余。但是,前面说了,Component不是语法冗余(好不好是另外一回事情),通过去掉Component来节省行数毫无意义。除非你能先证明Component抽象是无用的。而我前面就说了,你目前的文章并没有做到这个证明。

贺 -> 杨

知乎评论是无法编辑的。如果我前面把Binding.scala拼错了,向你道歉。

尤 -> 杨

光比代码短没有什么意义,Vue 写出来的代码也很短,但很少有人以这个作为难用不难用的标准。

说性能,没有数据空口说有毛用啊… krausest/js-framework-benchmark 你也来跑一个,碾压了所有实现再说别人井底之蛙也不迟。

贺老跟你说的意思是,你列举的种种(所谓)优点,没有一个重要到让一个写 js 的人有动力整个换一个生态,除非这人本来就熟悉 scala。另外就是,你推销自己的东西时候预设了用 js 的人都在井里,光这种居高临下的心态和口吻就不可能推销得出去。

杨 -> 尤

Vue.js 的 TodoMVC 例子中的 JavaScript 代码行数比 Binding.scala 的 Scala 代码长。vue/js、Binding.scala

当然这样比较,对 Binding.scala 不太公平。因为 Vue.js 除了需要编写 JavaScript 以外,还需要额外编写 HTML 模板。而 Binding.scala 的 Scala 文件中有一半左右的代码都是 HTML 模板。

不过没关系,虽然对 Binding.scala 不公平,但 Binding.scala 还是能赢。

所以您说的“Vue 写出来的代码也很短”就是井底之蛙。

尤 -> 杨

你那么多东西挤一行里面,空行那么少,比行数有意义么… 是来搞笑的吧?想要的话我分分钟可以把 Vue 的 todomvc 行数压得比你的短。行了,你这样的态度我也没兴趣理你,连 Vue star 零头的不到的项目继续自娱自乐去吧。

杨 -> 尤

Binding.scala的TodoMVC最长的一行是68行,有139个字符,是个注释行。

Vue的TodoMVC最长的一行是25行,有218个字符,塞满了那么多东西。

您要把代码行数压得比Binding.scala的话,其实也不难,大概一行塞2000个字符就行了吧。

尤 -> 杨

不好意思,啪啪啪 Edit fiddle - JSFiddle <- 连模板在内 135 行,而且模板还带折行的哟

尤 -> 杨

性能方面,期待你来个比 Inferno 速度更快的跑分,人家用的可是 Virtual DOM 哟,我等着你哟。当然,做不到的话,大方的承认自己是井底之蛙也可以。

尤 -> 杨

呃,之前链接的 jsfiddle 打错一个字,修正以后的版本:Edit fiddle - JSFiddle ;)

杨 -> 尤

135行真的非常厉害,赞!

不过还是有些美中不足的地方,比如您的写法牺牲了复用性,把整个应用的全部HTML模板集中在了一起,如果要是个多页应用,需要复用footer的话,就比较困难。

再比如说,您的写法,相比ReactJS,缺少了类似PropTypes的Model的类型检查功能。

我确实被打脸了,毕竟Binding.scala的TodoMVC,如果不想牺牲复用性和类型安全的话,也要126行呢。

我承认我过去小看了Vue,今天让我刮目相看了,Vue只比Binding.scala多了9行还是很了不起的。

尤 -> 杨

好了,嘴硬有什么意思呢,我都说了 135 行的模板是带折行的,不折行这 9 行瞬间就回来了,水分想要多少有多少。你真要比不如比总字符数:Vue 的版本 4117 chars,你改了半天以后的这个新版本 5353 chars… oops,整整比 Vue 多了 30% 的代码量。你再努力下?

尤 -> 杨

还有啊,你这新版本最多也就是把模板切成了几个 partial,handler 和数据全在一个 scope 里面,明明是强耦合的一堆东西,也好意思叫可复用?

杨 -> 尤

对比了 Edit fiddle - JSFiddleScalaFiddle ,从示例代码行数看,Vue的宏观架构十分优秀。即使有复用性的问题,也瑕不掩瑜。

然而,如果逐行对比Vue和Binding.scala的不同写法,我却发现,Vue节省的30%的字符数,反而体现了Vue在API设计层面非常臃肿。

杨 -> 尤

把绑定变量渲染成文本:
* Vue:<span>{{data}}<span>
* Binding.scala:<span>{data.bind}</span>

杨 -> 尤

把不绑定的变量渲染成文本:
* Vue:<span>{{* data}}<span>
* Binding.scala:<span>{data}</span>

杨 -> 尤

把绑定变量设置上属性:
* Vue:<span :class="data"></span
* Binding.scala:<span class={data.bind}></span>

杨 -> 尤

设置事件处理器:
* Vue:<a @click="clickHandler"></a>
* Binding.scala:<a onclick={clickHandler}></a>

杨 -> 尤

条件渲染:
* Vue:<h1 v-if="ok">Yes</h1><h1 v-else>No</h1>
* Binding.scala:{ if (ok.bind) <h1>Yes</h1> else <h1>No</h1> }

杨 -> 尤

条件隐藏:
* Vue:<h1 v-show="ok">Hello!</h1>
* Binding.scala:<h1 style:display={ if (ok.bind) "block" else "none" }>Hello!</h1>

杨 -> 尤

列表渲染:
* Vue:<ul><li v-for="item in items">{{ item.message }}</li></ul>
* Binding.scala:<ul>{ for (item <- items) yield <li>item.message.bind</li> }</ul>

杨 -> 尤

设置条件事件处理器:
* Vue:不支持
* Binding.scala:<a onclick={ if (ok.bind) clickHandler1 else clickHandler2 }></a>

杨 -> 尤

Binding.scala只在Scala原生语法基础上再提供一个bind语法就支持了上面所有功能,而Vue发明了“:xxx”、“@xxx”、“v-xxx”、“{{* xxx }}”这么多API和特殊语法、破坏正交性、紧凑性、一致性,功能仍然比Binding.scala更弱。我觉得您为了在击键次数方面战胜了Binding.scala而付出的代价有点得不偿失。

这些问题可能Vue的粉丝不清楚,但尤老师您自己还是得好好想想。我建议尤老师不要试图列举所有用户可能用到的功能。因为一旦用户需要的功能尤老师您没想到,Vue就歇菜了。比如您看,Vue就没办法根据绑定条件动态改变事件处理器。所以我觉得您可以在Vue 3.0放弃这些臃肿的API,模仿Binding.scala的API重新设计,不再以优化击键次数为设计目的,那么说服Teambition改用Vue还是挺有希望的。

杨 -> 尤

尤老师对耦合和复用的认识,让我有点失望啊。

初学编程的小朋友都知道提个函数就能复用,尤老师还在追求“组件”这种形式主义的东西。

Binding.scala推荐的方式是直接把partial写成全局函数,直接调用就可以复用了。

至于handler,和相关的HTML属于同一个复用单位,必须放在一起才能保证内聚性啊。

您如果要黑的话,唯一的黑点是ScalaFiddle不支持多文件,所以只能把所有复用单位写在一个文件里。

最后还是感谢一下尤老师的反馈,我调整了一下空行,把相关的handler和HTML写得近一点,以便体现内聚性。新版本放在ScalaFiddle,麻烦尤老师再帮我指正一下。

尤 -> 杨

你大概不知道 Vue 2 支持手写 render function 和 jsx… 偶尔可以跳出你的井看看,外面的世界很大的。

杨 -> 尤

尤老师,我就是想教您设计API。

Vue现在的API,90%都是没有一丁点用的,这样的设计是不合格的。

您如果想提升一下API的技能,您可以学习一下Binding.scala的API。

杨 -> 尤

尤老师您真的觉得Vue+JSX就像Binding.scala一样简洁高效吗?

您先把您那臃肿的API删掉90%再说吧。

我觉得您可以想一想,为什么Binding.scala里没有$slots、$children、directive、Component、$parent、$root、$refs、$scopedSlots、$watch、$destroy、$force、key、……所有这些API,然而,Binding.scala功能还比Vue强呢?

评论