微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

扯扯“Model Driven UI”

2016-02-09 21:33 前端大全

(点击上方,可快速关注)

来源:刘骥(@刘骥-JimLiu)

网址:http://jimliu.net/2015/12/30/model-driven-ui-blah-blah/


为什么我认为对于构建应用程序而言,MVVM/React是比jQuery更容易的方式?


文章比较浅,科普性质,大神们别嫌弃。


“传统”方式


用一种“传统”的思路,我们要更新页面某一个部分的UI,应该这么做:


$.get('url', function(data) {

  ui.find('#name').html(data.name)

})


这个例子应该是一个典型的场景


  • 拉数据

  • 找元素

  • 改属性


为什么核心在于“找元素”呢?由于要尽可能的优化UI的性能,只能做最小更新操作,那么就需要找到发生变化的那个字段所需要的元素,单独对其进行操作。


所以jQuery的核心就在于query,首当其冲就是它能最快捷的帮我们query出需要的元素来,很好的满足了一个JS库的核心需求。当然它的另一个优势就是它的API设计得太简便了,简直是不会JS都能用,入门成本之低令人发指。


这么做的问题


一句话


UI被设计为依赖Model,Model不应该依赖UI。


如果实现成贫血Model层,就会在逻辑代码里面去进行上面的query-update操作,如果是充血Model层那可能就在Model里。不论怎样,这样做都违背了上述依赖关系。


很简单,当UI发生变化(这种变化在迭代当中非常频繁)的时候,不仅需要修改UI本身,也需要去修改逻辑代码或者Model层,比方说#name这个ID换掉了,得换个选择器;比方说span变成了textbox,得把.html()换成.val();比方说整个UI层重新换了一套CSS命名规范,或者上了一个className混淆方案,可能让所有的addClass/removeClass/hasClass全瞎;比方说运营需要“重要的事情说三遍”于是同一个字段要被连续展现3次;比方说相册改版,啥没变,惟独从井字格变成轮播图了……


这些本身应该是UI的事儿——毫无业务逻辑在里面——却需要去改逻辑代码,依赖关系颠倒过来了,形成了anti-pattern。


所以现在流行说“单向数据流”,它是对上面所说的依赖关系的一个形象描述。


Model Driven UI


这概念谁说的来着,好像是Polymer。其实在12年的某个项目里,我就在尝试这个方式,当然,举步维艰。


一个很糙的方式


当时的主要矛盾是,我们也实现了单向数据流,所有UI操作都调用Business层(相当于Controller)的接口,UI保持对Model的严格只读。但Business层修改完了Model之后,下一步就非常难了,为啥难呢?因为“Model变了,Drive不起UI来”。


如果Model只有一个简单粗暴的change事件,那么UI就倒了八辈子的大霉了,它根本不知道到底变了什么,没法做最小的UI更新,那么性能上基本先Say Goodbye了。


于是实践上的问题就来了,Business层在修改Model的时候需要如履薄冰地触发一个“合理地小”的事件——不能太大,这样UI大面积做无用的更新;不能太碎,这样UI还需要做一个batch更新机制。

这样的结果肯定就是事件的种类会随着use case增多而大幅度增多,而可怕的就是UI必须对这些新增的事件一一作出响应,哪怕它跟之前某一个事件差别相当之小。


这当中自然也就隐含了Model对UI的间接依赖,逻辑代码需要对UI有比较深入的了解,才会知道怎样去触发一个事件它才会“合理地小”。


有了batch update,可以把Model的change做到字段级别的CRUD事件了,但UI需要关心的事件就会呈一个数量级的增加。等于原本在逻辑代码里集中更新UI,变为了在UI里(借助batch update)分散更新——事儿没变少,就是换了个人在干。


至少是解决了一个依赖倒置的问题,UI通过字段来访问Model,通过事件来订阅更新自己,而Model则几乎不会对UI产生直接依赖了,极端一些,Model对于UI是不是DOM都可以不关心了。


没那么糙的方式


现在有了MVVM和Virtual-DOM了,batch update也都是标配,Business层可以肆无忌惮的对Model进行任何粒度的CRUD。UI也不需要监听Model上的各种事件了——简单的说来,虽然整个数据流没有变,但是每一个环节都变简单了。


所以MVVM和Virtual-DOM解决的问题是数据绑定/数据展现吗?是,也不全是。更深究地说,它们解决的问题是帮助UI和Model之间“脏活累活谁来干”的问题——都没人干,于是只能让框架干了。从此以后,


对于Model而言:“老子就管写,你爱读不读。反正我的值是对的,用户看到展现不对那都赖你。”


对于UI而言:“老子就歇着,你爱咋样就来弄我两下,但是活儿得好,别让我太累,用户嫌卡那就怪你。”

至于Model如何Drive UI,Angular(脏检查)、React(Virtual-DOM)用的办法是主动的发现Model的变化,然后去推动UI更新;Avalon、Vue基于property getter的做法是被动的等Model发生变化。


除了Virtual-DOM以外,都需要对UI进行预处理,解析出一个UI Element -> property之间的依赖关系,知道每一个Element依赖了Model的哪个字段。把这张图反过来,就知道当一个property被修改时,它会影响那些个Element,从而实现最小更新。


而Virtual-DOM的最小化patch方案是通过tree-diff计算出来的,基于现代浏览器“老子for循环跑的飞快”的霸气,执行tree-diff的速度很理想。于是就直接不需要构建依赖关系,用起来更简单粗暴;进而在需要的时候有一定的优化空间,可以通过immutable这种方式来快速跳过tree-diff当中的某些环节。


所以在精心优化的情况下,Virtual-DOM应该最快的无疑,property getter有更强的适应性,天生就很快,但从外部去优化它很难。


React另一个优势是它的启动速度,由于不需要构建依赖关系,甚至是连parse模板都不需要(这一步相当于直接在构建JSX的时候已经做好了),它启动步骤就短多了,夸张地说,直接render就出来了。


使用property getter的方案对于Model层有非常微弱的侵入性(相比Knockout那是低多了),使用脏检查和Virtual-DOM对Model层都几乎没有侵入性。


当然上面所说的性能差异其实都没有那么大啦……只是因为我自己写过virtual-dom玩具,也看了Vue的源码,一点小结而已。


理想和现实的差距


在一个足够复杂的场景下,如果能践行Model与UI的依赖关系,程序的可测性(React还是谁来着,也管它叫Predictable,可预测)就有了一定的保障。


但是,很多情况下,没有那么理想,比如


  • 很多Model被展现一次就没事儿了,压根儿就没有动态修改

  • 很多Model只被在一处展现,因此它动态修改的时候,在UI改和在Model里改,工作量是一样的

  • UI的调整并没有那么理想化,无法解释为纯UI的问题,几乎每次调整都涉及到业务逻辑的调整

  • 无所谓视图逻辑和业务逻辑,我们认为展现形式是业务逻辑的一部分,并不是什么卵的视图逻辑


个人的感受


  • 程序怎么写,还得看活儿

  • 做Web App和做Web Page,取舍还是差别大

  • 怎么算Web App怎么算Web Page,还得看老板怎么想

  • 如若无所谓模式,无所谓架构,那一切都是白说,反正It works

  • 面向工资编程,终究还是为了出活儿快、下班早,需求变时别骂娘,早日升职加薪,当上总经理,迎娶白富美,走上人生巅峰



【今日微信公号推荐↓】

 
前端大全 更多文章 5个典型的JavaScript面试题(上) Limu:JavaScript的那些书 Web开发:我希望得到的编程学习路线图 JavaScript基础工具清单 常用排序算法之JavaScript实现
猜您喜欢 今天终结的两本书 C++11新特性Part9 关于 Fenng,再不爆料就老了(下) 第108讲 filesystem(1) 万万没想到Win10最赞的功能既然是它...