一、引言
一个理想的用户接口对用户最好是不可见的-仅在用户需要时提供选择,否则并不干涉他们的工作而让其专注于手头的工作。然而,这并不是一件容易的事情。如今,我们变得习惯于通过并不十分令人满意的UI进行日常工作,直到有人向我们展示一种更好的方法。现在,我们才逐渐认识到我们当前的方法在做这些事情时是多么吃力。
由于用于显示文档内容的基本web浏览器技术又被推进一步进而超出以前它们所能及的范围,所以,如今的互联网正在经历着这样的实现。
Ajax(异步JavaScript+XML)是一个非常新的名字,为Adaptive
Path的Jesse James Garrett所创建。其中,Ajax的某些部分以前被描述为动态HTML和远程脚本。
Ajax的出现不仅仅是一个新名字的问题。从技术和商业的角度看,围绕Ajax还有大量激动人心的东西。从技术上讲,Ajax实现了web浏览器技术中大量的尚未实现的潜力。从商业上看,Google和其它一些主要商家正在逐步使用Ajax技术,从而让公众认识到一个web应用程序所能做的事情。
以前我们习惯的典型web应用程序如今正在承受着巨大的压力,因为逐渐复杂的基于万维网的服务正日趋成熟并开始应用于互联网。各种新技术争相涌现出来以克服这些问题,而Ajax仅使用现有的互联网技术就能够更好地表达这些思想。
利用Ajax,我们重用了一堆原有技术但却扩展了它们原来所能及的范围。我们需要能够管理这种我们引入的复杂性。本文将讨论怎样实现这些技术,而且还要讨论一下管理大型Ajax工程的问题。我们将介绍Ajax设计模式及其怎样帮助我们完成工作。设计模式帮助我们捕获我们的知识和经验,用我们现在的技术并且使之与其它对象进行通讯。通过把规则引入到代码基之上,它们就能够方便创建应用程序-可以据变化对工程加以修改和扩展。使用设计模式进行开发甚至是一种喜悦!
为什么说Ajax是丰富的客户端?
构建一个丰富的客户端接口比设计一个WEB页面要复杂。那么是东西导致我们这样做的?好处有哪些?什么是丰富的客户端?
一个丰富的客户端有两个关键特点:它是丰富的,而且它是一个客户端。
让我稍作解释。丰富指的是客户端方式。一个丰富的客户端模型-是指它能够支持各种输入方法且能够直观又非常及时地作出响应。尽管我们称其为"丰富的",但是它必须与象字处理器和工作表等现代桌面应用程序一样好才真正丰富。下面让我们看一下为达此目的所具体要求的实现技术。
二、比较用户体验
在这里,让我们讨论一个工作表程序的实例。当我在工作表输入一些简单的公式时,我可以有几种方式与之交互-现场编辑数据,用键盘和鼠标导航数据和通过鼠标拖动重新组织数据。
当我在操作这些时,软件给我反馈-鼠标光标形状改变,当我在按钮上移动时按钮高亮,选定的文本改变颜色,高亮的窗口和对话框以不同形式显示,等等(图1)。
图1
这个桌面工作表应用程序说明了多种用户交互的可能性。
|
这些是当今用户丰富的交互的主要表现。这样的工作表应用程序就是一个丰富的客户端吗?还不是。
在一个工作表或类似的桌面应用程序中,逻辑和数据模型都在一个封闭的环境中运行-在此它们彼此都能清晰可见,但是却把外界拒之门外(图2)。我的客户端定义是一个程序-它能够与一个不同的独立的进程通讯-典型地它运行于一个服务器上。传统地,该服务器比客户端更大更强壮并且存储了海量信息。客户端允许终端用户观看和修改这些信息,并且如果有一些客户连接到同一个服务器上,它允许他们分享该数据。图3显示出一客户机/服务器架构的简单图解。
图2
一个独立桌面应用程序的图解架构。
|
该应用程序运行于其自身的进程之中-在其内数据模型和程序逻辑彼此清晰可见。在同一台计算机上运行的该应用程序的第二个实例除了经由文件系统之外无法存取第一个实例的数据模型。典型地,全部程序状态存储在单个的文件中-当该应用程序运行时它被锁定以阻止任何信息的同步交换。
图3 客户端/服务器系统和n层架构图解。
|
该服务器提供一个客户可以用之进行交互的可共享的数据模型。客户端仍然维持它们自己的部分数据模型以达到快速存取。多个客户可以与同一个服务器进行交互,而此时在单个对象或数据库行良好粒度级上控制的资源被锁定。该服务器可以是一个单个的进程,就象在90年代以前的早期的传统型客户端/服务器模型或由若干中间件层、外部web服务等组成的现代模型。在任何情况下,从客户的角度来看,服务器具有单个入口点并且可以被认为是一个黑盒子。
当然,在一现代的N层架构中,服务器将能与例如数据库这样的后端服务器通讯-这导致了中间件层的出现-它们既充当客户端又充当服务器端。典型地,我们的Ajax应用程序位于这个链的一端上-只担当客户端,所以我们可能把整个N层系统看作单个黑盒子-我们把它标记为服务器,以便于我们当前的讨论。
我的工作表只专注于它自己的存储在本地内存和本地文件系统上的数据。如果它架构良好,数据层和描述层之间的耦合可能相当松散,但是我无法把它通过网络分解与共享。所以,从我们的描述层目标来看,它不是一个客户端。
当然,Web浏览器是客户端,它连接web服务器并从中进行页面请求。这些浏览器具有一些丰富的功能来管理用户的web浏览,例如后退按钮、历史列表和多页面存储多个文档。但是如果我们把一个特定站点的web页面看作一个应用程序,那么这些通用浏览器控制便不能再关联到应用程序,就象Windows开始菜单或window列表相关于我的工作表一样。
让我们看一个现代web应用程序。主要因为每个人可能都听说过它,所以我们将选择Amazon-在线书商为例(图4)。现在,我把自己的浏览器指向Amazon站点;因为该站点从我的上次访问能够记得我是谁,所以它先给我显示一个友好的问候、推荐书列表和关于我已购买书的历史信息。
图4 Amazon.com首页。该系统记得我以前访问过该站点,其中可导航的链接是通用信息和私人信息的混合。
|
从建议列表中点击一个标题将把我导向一个独立的页面(也即,该屏幕闪烁一下,于是我就失去了几分钟前可以看到的列表)。于是新页面中又会充满各种上下文信息(见图5)。
图5 Amazon.com站点书籍详细资料页面。
|
再一次,大量的结合有通用和私人信息的超链接出现。尽管如此,大量的细节与图4所示极为相同-这,由于web浏览器的基于文档的操作,必须被重新转送到每个页面。
简言之,我向你展示了非常丰富的紧密联系的信息。而且我与这种信息交互的唯一方式是通过点按超链接并且填写文本表单。如果我在浏览站点时的键盘输入过程中睡着了并且第二天才醒来,那么在我刷新全部页面之前我不会知道新的哈里·波特书已经发行。我不可能带着我的列表从一个页面转到另一个页面,并且我不可能缩放该文档的一部分来一次观看多处的内容。
这并不是在诋毁Amazon,在非常有限的限定内它工作得相当优秀。但是与工作表相比,它所依赖的交互模型毫无疑问相当有限。
那么,为什么在现代web应用程序中存在这么多的限制呢?目前,存在很多技术上的原因。因此,现在让我们作进一步分析。
三、网络的潜力
互联网时代的伟大就在于世界各地所有的计算机互相联系,就象在一个非常大的计算资源之中。远程和本地过程调用变得很难区分,并且发行者已经不再清醒地了解它们在哪些物理机器上工作。
不幸的是,远程和本地过程调用是根本不相同的技术。
在网络上的通讯是昂贵的(它们是慢并且不可靠的)。当一部分非网络代码被编译或解释时,各种方法和函数就象在其上操作的数据一样被编码为存储在相同的本地内存中的指令(图6)。这样,把数据传递给一个方法并返回结果就相当直接。
图6 本地过程调用序列图-在此很少的元素如程序逻辑和数据模型都被存储在本地内存并能彼此直接看见。
|
其实在底层,为了发送和接收数据,很多计算运行于一个网络连接的两端(图7)。实际上,这种计算远不如沿着物理线路的运行更导致系统的减慢-各级的编码与解码遍及通讯的各个方面,从沿着线路传输的物理信息,把这些信息翻译为二进制的1和0,错误检查和重发送,到重新整合该二进制序列。
图7
一个远程过程调用序列图。在一台机器上的程序逻辑试图操作在另外一台机器上的数据模型。
|
调用函数的请求必须被编码为一个稍后将被串行化的对象(也即,被转换成一个线性字节集合)。然后,被串行化的数据被传递到应用程序协议(现在通常为HTTP)并且通过物理传输发送。
在远程机器上,该应用程序协议被解码,并且数据的字节被反串行化以创建该请求对象的一个副本。然后,这个对象被应用到数据模型和一个生成的响应对象上。为了联系该响应和调用函数,该串行化和传输层必须被再一次导航,最后导致一个响应对象被返回到调用函数。
这些客户端是复杂的但是适合于自动化实现。现代的编程环境例如Java和微软.NET框架都提供了这种功能的自由使用。尽管如此,当产生一个远程过程调用(RPC)时,在内部有大量的活动在进行并且如果这样的调用太自由的话,性能也会受到影响。
因此,通过网络的调用永远不会象调用本地内存中的一个方法那么富有效率。而且,网络的不可靠性(并因此需要重新发送失去的信息包)也使得这种低效在不断变化且很难预测。在你的本地机器上的内存响应性不仅更好一些而且相比之下可以被很好地定义。
这但与可用性有什么关系呢?已证明,其关系相当大。
一个成功的计算机UI的确需要模仿我们真实的世界期望。该交互的最基本原则之一是,当我们点按某东西时,它能够立即响应。在点按和响应之间的轻微的延迟都会带给用户迷惑并使之分神-把用户的注意力从手头的任务转移到UI本身。
必须做所有的额外工作来穿越网络常常就足已减慢一个系统,以至于该延迟变得相当引人注意。在一桌面应用程序中,我们需要做出糟糕的可用性设计决策来使得应用程序感觉起来充满错误或不具有响应性,但是在一个联网应用程序中,不需要我们关心这些!
由于网络潜力的不可预测性,这种可察觉的错误来来去去,并且测试应用程序的响应性也可能变得更为困难。因此,网络潜力是真实世界应用程序具有可怜的交互性的最通常的原因。
四、异步客户端
在实际中,我们必须尽量使UI响应独立于网络活动。幸好,一段固定时间的响应经常就足够了,只要它是及时的。让我们再次看一下实际中的问题。我的早上例程的主要任务之一是唤醒我的孩子们上学。我可以站在他们上面戳他们直到他们起床并穿上衣服,但这是一相当花费时间的方式,留下很长的一段时间我几乎无事可做(图8)。
图8异步响应用户输入序列图
|
在这个序列图中,时间的过渡是垂直的。阴影部分的高度指示了我被阻塞进一步输入的时间长度。
我需要弄醒我的孩子,外盯窗户,并且忽略了猫。孩子们将通知我-这时他们因要求吃早餐而被正确唤醒。就象服务器端进程一样,孩子们醒得很慢。如果我使用一个异步的客户端模型,我将等待很长时间。只要他们能够咕哝一声,我就能醒来,然后我就可以继续轻松地干别的事情并且在需要时检查他们。
用计算机术语来说,我在此所做的是在一个独立的线程中激发一个异步的过程。一旦启动它们,我的孩子们就会在他们自己的线程中自己醒来;而我-父线程,不需要与他们同步,直到他们通知我(通常使用一个请求)。尽管他们正在醒来,但是我无法与他们的客户端进行通讯,好象它们已经起床并穿好衣服了,但是我能确信它一定会及时发生的(图9)。
图9
一异步响应用户输入序列图。如果我使用一个异步的输入模型,我能让孩子们通知我他们开始醒来。然后,当醒来发生时,我能继续我的
另外的活动并且有一段很短的时间保持阻塞。
|
无论使用任何UI,创建一异步线程来处理任何冗长的计算并且让它在后台运行,而用户继续处理其它事情都是一种很好的解决方案。当该线程启动时,用户必然被阻断,但是这可能在很短的一段可接受时间之内发生。由于网络的潜力,一种不错的实现是把任何RPC当作潜在的冗长过程并异步地处理它。
该问题和这种解决方案都是良构的。网络的潜力早已出现在老式的客户端/服务器模型中-这使得糟糕设计的客户端在试图到达一个过载的服务器时滞留到令人无法承受的程度。在当今互联网时代,网络的潜力使得你的浏览器在web页面间来回切换时经历了巨大的挫败。我们不可能消除这种潜力;但是我们知道通过异步地处理远程调用可以处理它,对不对?
不幸的是,对我们绝大多数web开发者来说,并没有捕获到这一点。
HTTP是一个请求-响应协议,该协议是单向的。客户端可以联系服务器,但是服务器不能与客户端开始一个通讯。确实,该服务器不能从一次到另一次的请求中记住客户端。
多数使用现代语言如Java、PHP或.NET的web开发者都会熟悉用户会话的概念。HTTP按照它的最初设计良好地工作着,而且它已经被改编来实现更为灵活性的功能。然而,我们的异步回调解决方案的关键在于客户端被再次通知:当创建线程时是第一次而当线程完成时是第二次。直接的HTTP和经典web应用程序模型无法为我们完成这一点。
如Amazon所使用的经典web应用软件模型仍然是基于页面概念设计的。一文档被显示给用户-包含一个列表的链接和/或表单元素-它们允许它们提交给进一步的文档。完全有可能以这种方式大规模地与复杂数据集交互,并且如Amazon和其它站点所展示的-完全可以基于这一经验构建一种商业运作。
这种客户端方式已经根深蒂固于过去十多年间的每天的商业互联网之中。友好的WYSIWYG
web创作工具把我们的站点可视化为一个页面集合。服务器端web框架把这种页面间的转换建模为状态转换图。经典web应用程序,在页面刷新时,与不可避免的缺乏响应紧密结合,不可能容易地求助于异步处理器解决方案。
但是Amazon基于其网站已经取得了商业上的成功。当然,经典web应用程序不可能象那样不可用?为了理解为什么web页面可以适合于Amazon而不适用于每个人,我们应该考虑一下使用模式的问题。
五、长期与短暂使用模式
软件可用性专家Alan Cooper对于使用模式下过重要的结论,并且定义了两个关键的使用方式:短暂的和长期的。一个短暂的应用程序可能每天都被使用,但只在是一段时间内且通常只是作为第二活动。而相反,一个长期的应用程序必须每次连续数小时地有效地处理用户的全部注意力。
许多应用程序其实都是短暂或长期使用的。一个作家的字处理器是一长期的应用程序,例如,其中包括了许多短暂的功能,例如文件管理器(经常嵌入到字处理器中,如一个文件保存或打开对话框),一本字典或拼写检查程序(经常是嵌入的)以及与同事交流的一个电子邮件程序等。对一个软件开发者来说,文本编辑器或集成开发环境(IDE)则是他们长期使用的,还有调试器。
长期使用的应用程序常常也是满怀激情使用的。请记住,一个良构的UI应该是不可见的。这种使用的一个良好度量是对用户UI工作流的影响,这样就提醒了用户它的存在。如果我只是简单地把文件从一个文件夹移动到另一个文件夹并遇到一个2秒钟的等待,我可能比较高兴。如果
我在操作一个绘图程序或在一个繁重调试会话中间遇见同样的一个2秒钟等待,我可能变得有点不安。
Amazon是一短暂应用程序,eBay和Google以及大多数的非常大型的公共的基于web的应用程序也是这样的程序。自从出现互联网后,权威专家们已经预言了在基于Web的解决方案的冲击下传统型的桌面办公室套件的归宿。然而,10年过去了,它还没有发生。基于Web页面的解决方案对于短暂的使用已经足够了但是对于长期的使用却不够。
六、忘却Web
幸好,现代web浏览器相似于原来的针对远程文档服务器的客户端理想-这极相近于瑞士军刀相似于一种过时的电石狩猎工具。在冲向创建最引入注目的浏览体验中,交互式小发明,脚本语言和插件都将/正在犹豫不决中关门。
可以把Ajax看作一个针对于浏览器战争中被误解的行为不正常的孩子的康复中心。通过提供一些指导和一个可在其中操作的框架,我们能把JavaScript转换成互联网中的一个有用的模型成员,它能够提高一个web应用程序的实用性并且在该过程中不会激怒用户或给浏览器显示需求量等垃圾信息。为此,有一些成熟的、易于理解的工具可用来帮助我们。设计模式就是这样一种工具-常用于我们的工作中并且在本文中多次参考。
引入一种新技术是一个技术的和社会的过程。一旦该技术出现了,人们就需要弄明白该用它来干些什么,并且第一步常常是使用它,似乎它是一种原有技术且更为熟悉。因此,早期的自行车被当作是木马并且沿着地面推着人的脚来骑。随着这种技术为更广多的用户所认识,又一批革新者将发现使用这种技术的一些新的方法-添加了改进如踏脚板,制动闸,齿轮和充气轮胎。随着每次改进,自行车变得越来越不象马了(图10)。
图10现代自行车的发展
|
相同的过程也适用于web技术的发展。Ajax背后的技术能够把web页面转换成某种相当新的东西。为了从根本上理解Ajax技术的潜力,我们必须放开web页面的概念,并且在这样做时,要忘却很多以前我们所做的许多假设。在过去很短的几个月间由于Ajax一词的出现,以前我们所用的很多技术都要被抛弃了。 |