前言
最近一直在做Web前端开发,学习js,写着写着,发现越来越像之前做过的android开发了。这倒不是说我把js当成java来写了,而是从一些基本思路上来看,互联网产品都或多或少有着相似之处。当然,都是基于REST风格的前后台交互,统一,简单。在这里总结成模型。外国人也常常提出各种模型,主要是方便理清思路,所用到的概念和技术不一定是新提出来的,而UMD模型提到的技术则更是毫无新意可言,如果你是Web开发老手,就不太需要了,我想你心中一定有自己的一套模型。这个模型可能更多是帮助新手认识互联网开发的所需考虑的各个方面。
假设:
用户使用 Web app是希望通过一系列交互来提供或找到某些信息
这个假设很多情况下都成立,因为其实啥都没说。不过游戏能不能算Web app呢,看如何理解了。个人没开发过游戏,没发言权,所以暂时不算好了。
UMD: UI, Memory, Database
把假设引申一下就可以得出,整个Web其实就是信息流的交互,因此,我们可以从数据的角度来观察任何一个Web app的架构,数据存在于哪些位置,做怎样的流动,产生怎样的后果。数据一般来说存在于以下位置:
- UI 用户界面,数据按照一定格式直接呈现给用户,提供信息
- Memory 内存,客户端或者浏览器里暂存的数据,在app生命周期中存在,与UI对应
- Database 数据库,存在于网站后台,用于数据的持久化存储,静态的html应该可以包括其中,如果通过资源(resource)这个词来描述可能更适合。
- Cache 缓存,缓存可能存在于客户端的本地数据库或者后台的数据库中,可选项,其与Memory作用类似,可以用相同的思路讨论,或者成为UMCD模型进一步讨论,这里不多说了。
UMD Consistency and Update
既然我们可以把数据分成三块,这三块数据最基本要保证:一致性。即三部分数据所表达的信息一致,换句话套用一下就是:所见即所得。
因此,三处数据则至少有一下三类方法来更新数据:
- updateUI()
- updateMemory()
- updateDatabase()
这里的update不是指狭义上的CRUD中的update,我们可以看成是一种对数据的操控,包含了CRUD,让这个数据变的更有效,并得到相应的返回。
另一方面,用户界面需要提供用户交互,让用户找到自己想要的东西。因此,在UI上还会至少有一类方法,处理界面上出现的用户交互:
handleEvent()应该不仅包括从网页上进行的交互,用户输入的url,以及在别的网页点击链接进入这个网页,都应该包括其中,不过这部分浏览器替我们做了。从计算机一出生到现在,其做的最基本的一件事应该就是接受input,提供output,这两点在Web app中可以对应成handleEvent()和updateUI(),因此这个模型我想至少不是错误的。有了这四个方法,我们就可以绘制一般的Web app的程序运行模型。

一致性原则告诉我们:
三处数据任何一处的数据更新,另外两处数据都要同时也得到更新。
在图中看起来UI和Database是不能直接通信并互相更新的,Memory起到了一个枢纽的作用。但其实现实的Web开发中,很多时候是没有Memory这一层的,甚至在几年前,认真对待内存中的数据可能都是一件非常滑稽的事,因为那是浏览器要考虑的。但随着Web app的发展,趋势是其越来越像一个客户端,需要有自己的固定的内存分配来存放数据。因此我们讨论的时候就把Memory带上,来强调在实现前台的时候需要考虑Memory。我最近写的代码中就确实需要维护内存中的数据,通过Memory作为桥梁来更新UI数据事实上可以认为或者实现成updateMemory()和updateUI()需要同时被调用。
UMD Realization
模型是用来指导实践的,即在具体的Web app实现场合,我们如何利用这个模型帮助我们理清思路,并完成各个部分的开发。
User Interface
在web app的场合,UI主要由HTML和CSS来呈现,通过JavaScript来动态控制。
Jquery是很经典的事件驱动的Js库,能够很好的绑定事件到回调函数来处理事件。原生的JavaScript当然更是可以绑定事件了,只是写起来很罗嗦,并且有各种兼容性问题。
Jquery库也可以进行DOM、CSS操作来更新用户界面,以及各种实用的动画。同时,用JavaScript来控制DOM总是一件从编码到浏览器调用都很不开心的一件事,很容易写的效率很低,相应的,就有一些前端模板出现,例如mustache,写一定的模板之后,mustache能够为你生成相应的html代码。HTML5标准中提供了更多的帮助你改善UI的工具。
根据一致性原则,updateUI()的原因可能是另外两处数据发生了变化,而在模型中,鼓励内存的变化来调用updateUI(),而不是后台的数据返回后直接更新。注意,是鼓励,但不是所有场合。
Memory
Web应用发展到现在,很多应用仍然不需要特别注重存在于内存中的数据,只是单纯的把后台的页面呈现出来就可以了。但随着Web app的复杂和功能性越来越强,在内存中存储数据能够有效降低网络请求数量和页面响应速度。HTML5中规定了一些在浏览器端的数据存储功能,解决问题的思路和放在内存中类似,在处理大量数据的场合更适合。
内存中的数据内容一般是UI中呈现数据在内存中的映射,首要问题是数据结构,数据如何进行存储,Js中提供的object普通对象和function函数对象能够用一种很简单、基本的结构来存储数据:键值对和数组的集合。这个也可以在JSON的数据格式和object literal的声明方式来得到体现。即
{
key: value,
key_array: [v1, v2, …],
key_obj: { obj_key: obj_value},
}
考虑将数据和业务逻辑分开是一种符合趋势的思路。显式、明确的考虑updateMemory()函数能够让人对数据把握的更清楚,特别是在Js这种灵活性太高的语言中,也使得代码更容易维护。虽然Js的函数式语言特性让内存中的数据可以封装在各种函数的闭包中,但没有组织的零散数据的可维护性不太好,虽然写起来很快。
updateMemory()方法的调用者可能来自UI或者后台数据库,既然Memory是一个信息的桥梁,那么Memory既然是数据的集中地。例如用户输入的handleEvent()需要修改内存中的数据,而后台数据更新后的返回,也需要修改内存中的数据,或者至少看看内存中数据是不是已经过时了。
Database
后台的数据一般都存在数据库中,辅以文件系统。使用REST风格的结果是,统一认定后台的数据位资源,后台所要做的就是接受前台的请求并CRUD特定的资源。对于前台来说,后台就是一个黑盒子,只有提供API接口和数据协议来交互。REST风格的API接口其实就是一段特定的URL,数据协议基本上通过JSON格式规定,从而保证简单、易用。
updateDatabase()的调用者一般来说是Memory,即当Memory需要发生改变的时候,去改变后台的数据。不过Web程序中很多时候不用涉及到Memory,所以也可能是直接的用户事件调用的,例如提交一个表单。
在ajax大量广泛的如今,很多时候连表单和上传文件都希望能够异步实现,提升用户体验。异步通信的好处就在于,可以很快的响应用户界面而不必等待后台的操作完成。但是与此同时,这将可能产生UI、Memory两者和Database的数据不一致。在后台操作完成之后,及时的updateMemory()并通过其updateUI()是很有必要的,特别是当后台操作失败的时候,需要及时修正Memory中的数据,并提示用户。
结语
暂且写成这样吧,主要解释了三种数据:UI、Memory和Database,以及相应的四种方法:updateUI(), updateMemory();updateDatabase和handleEvent()。具体实现的时候,脑袋里带着这几样东西去写东西,应该比啥都不想一个事件一个事件的去写来的高效,鲁棒性强。不过我个人写前端也没多久,后台也只用django写过一个学期,认识或许还不是很到位。接着code一阵子,看需不需要把这个模型弄成前端框架啥的。模型中所有的概念现有的框架和语言都已经够用了,只是不是那么明确而已。