Ajax实战( Ajax in action中文版 1.1为什么需要Ajax富客户端 建造一个富客户端[2]毫无疑问要比设计一个网页复杂。付出这些额外的努力,动机何在? 需要付出什么代价?而且……等一下,富客户端到底是什么? 富客户端的两个要点是:第一,它是“富”的:第二,它是“客户端”。 这好像是一句废话,别急,待我稍作解释。“富”是指客户端的交互模型,要有多样化的输 入方式和符合直觉的及时反馈手段。说简单点儿,一个“富”的应用使用起来应该像是在使 用现在的桌面应用一样,例如,就像是使用字处理软件(Word)或电子表格软件(Excl) 接下来,我们有必要仔细地考察一下所要涉及的各个方面。 1.1.1比较用户体验 花几分钟使用一下你选中的应用(浏览器除外),记下它用到了哪些用户交互,然后马上回 来。为了简短起见,我举一个电子表格的例子,但是,这里所涉及的要点是通用的,足以针 对文本编辑器上的各种情形 好,我们开始。先在电子表格中随便输入几个等式,注意到,可以以几种方式进行交互:编 辑数据,用键盘和鼠标浏览数据,还可以使用鼠标拖拽来重新组织数据。 我做这些操作的时候,程序给了我反馈。移动鼠标的时候,光标改变了形状:当鼠标停在上 面的时候,按钮变亮了;选中的文字也改变了颜色。窗口或者对话框被选中的时候,也和平 常显得不一样了,等等(图1-1)。这些就是所谓“富”的交互。当然了,仍然有一些有待 改进的地方,但这是一个好的开始 电子表格就是一个富客户端程序了吗?当然不是 在电子表格或者类似的桌面应用中,业务逻辑和数据模型是在一个封闭的环 境中运行的。在这个环境中,它们彼此清晰地了解对方,并且可以互相访问,而环境之外的 东西,对于它们来说是未知的(图1-2)。那么客户端又是什么呢?它是与另一个独立的进 程相互通信的程序,后者通常运行在服务器上。一般来说,服务器总是要比客户端大一些 能力强一些,配置更好一些,因为在服务器上通常要存储浩如烟海的信息。客户端程序使得 最终用户可以查看和修改这些信息,当多个客户端连接在同一个服务器上的时候,可以在它 们之间共享这些信息。图1-3展示了一个简单的客户服务器架构
Ajax 实战(Ajax in action 中文版) 1.1 为什么需要 Ajax 富客户端? 建造一个富客户端[2]毫无疑问要比设计一个网页复杂。付出这些额外的努力,动机何在? 需要付出什么代价?而且……等一下,富客户端到底是什么? 富客户端的两个要点是:第一,它是“富”的;第二,它是“客户端”。 这好像是一句废话,别急,待我稍作解释。“富”是指客户端的交互模型,要有多样化的输 入方式和符合直觉的及时反馈手段。说简单点儿,一个“富”的应用使用起来应该像是在使 用现在的桌面应用一样,例如,就像是使用字处理软件(Word)或电子表格软件(Excel)。 接下来,我们有必要仔细地考察一下所要涉及的各个方面。 1.1.1 比较用户体验 花几分钟使用一下你选中的应用(浏览器除外),记下它用到了哪些用户交互,然后马上回 来。为了简短起见,我举一个电子表格的例子,但是,这里所涉及的要点是通用的,足以针 对文本编辑器上的各种情形。 好,我们开始。先在电子表格中随便输入几个等式,注意到,可以以几种方式进行交互:编 辑数据,用键盘和鼠标浏览数据,还可以使用鼠标拖拽来重新组织数据。 我做这些操作的时候,程序给了我反馈。移动鼠标的时候,光标改变了形状;当鼠标停在上 面的时候,按钮变亮了;选中的文字也改变了颜色。窗口或者对话框被选中的时候,也和平 常显得不一样了,等等(图 1-1)。这些就是所谓“富”的交互。当然了,仍然有一些有待 改进的地方,但这是一个好的开始。 OK,电子表格就是一个富客户端程序了吗?当然不是。 在电子表格或者类似的桌面应用中,业务逻辑和数据模型是在一个封闭的环 境中运行的。在这个环境中,它们彼此清晰地了解对方,并且可以互相访问,而环境之外的 东西,对于它们来说是未知的(图 1-2)。那么客户端又是什么呢?它是与另一个独立的进 程相互通信的程序,后者通常运行在服务器上。一般来说,服务器总是要比客户端大一些, 能力强一些,配置更好一些,因为在服务器上通常要存储浩如烟海的信息。客户端程序使得 最终用户可以查看和修改这些信息,当多个客户端连接在同一个服务器上的时候,可以在它 们之间共享这些信息。图 1-3 展示了一个简单的客户/服务器架构
Eile Edit yew nsert Format Tools Data window He 日品 m→%4日出|口回 出sh/h/h山 图1-1这个桌面电子表格应用展现了用户交互的众多可能性。被选中单元格的行列标题都 是突出显示的:按钮在鼠标移上去的时候会显示提示信息;工具栏上排列着各种丰富的控件; 单元格也可以交互地查看和编辑 进程 进程2 逻辑 逻辑 数据 模型 文佯统 图1-2一个独立的桌面应用的架构示意图。应用运行在它自己的独立进程之 中,数据模型和程序逻辑能够彼此“看到”对方的存在。除了通过文件系统之外,同一个应 用的第二个运行实例[3]没有办法访问到第一个运行实例的数据模型。通常来说,整个程序 的状态都保存在单个文件中,当应用运行的时候,这个文件会被加锁以阻止其他的进程同时 访问
图 1-1 这个桌面电子表格应用展现了用户交互的众多可能性。被选中单元格的行列标题都 是突出显示的;按钮在鼠标移上去的时候会显示提示信息;工具栏上排列着各种丰富的控件; 单元格也可以交互地查看和编辑 图 1-2 一个独立的桌面应用的架构示意图。应用运行在它自己的独立进程之 中,数据模型和程序逻辑能够彼此“看到”对方的存在。除了通过文件系统之外,同一个应 用的第二个运行实例[3]没有办法访问到第一个运行实例的数据模型。通常来说,整个程序 的状态都保存在单个文件中,当应用运行的时候,这个文件会被加锁以阻止其他的进程同时 访问
进1 @ 见 务番 务器(例如数据庳 康务群 因持网忠务 图1-3客户服务器系统和n层架构的示意图。服务器提供了共享的数据模型,客户端与该 数据模型交互。客户端同时还维护数据模型的一部分,以获得快速的访问,但是它将服务器 端的模型当作业务领域对象的最终表示。多个客户端可以与同一个服务器交互,当然,这需 要有合适的资源锁定机制和合理的对象(或者数据行)隔离措施作为保证。服务器可以是单 进程的,就像在20世纪90年代早期和中期传统的客户/服务器模型中一样,也可以是由很 多个中间件层或者多个Web服务等组成。在任何一种情况下,从客户端的角度来看,服务 器都有一个单独的接入点,可以看作是一个黑盒 在现代的n层架构中,服务器往往要和更远的后端服务器(例如数据库)通信,因此被称作 中间件”的层同时扮演着客户端和服务器的角色。我们的Aax应用位于这个链的一端, 它仅仅是作为客户端,因此为讨论方便,我们可以把整个n层系统看作是一个标记为“服务 器”的黑盒 我的电子表格应用只需要管理它自己保存在内存或本地文件系统中的少量数据。如果架构设 计良好的话,数据和它的表现形式的耦合可以非常松散,但是我不能通过网络来分割或者通 过网络来共享它们。从这个意义上来说,电子表格应用不是一个客户端 与之相对应的web浏览器就是一个典型的客户端,它与Web服务器通信,请求需要的页面 浏览器有丰富的功能,用来管理用户的浏览行为,常见功能有回退按钮、历史列表和分页浏 览多个文档等等。但是当我们把特定网站的Web页面看作是一个应用时,这些通用的浏览 功能实际上和应用关系不大,充其量也就如电子表格和 Windows的开始按钮或者窗口列表 之间的关系。 我们来考察一下现代的Web应用。为了简单起见,我们选择了“地球人都知道”的在线书 店 Amazon com(图1-4)。在浏览器中打开 Amazon网站,因为在此之前我访问过,它会给 我显示一个友好的问候、一些推荐书目,还有我的购买历史信息。 点击推荐书目中的任何一条,就会转到另外一个页面(此时,页面要刷新一下,在这几秒钟 内我什么也看不到)。新页面是该书的相关信息:书评、二手书报价、同一作者的其他著作, 以及以前我浏览过的其他书籍(图1-5)
图 1-3 客户/服务器系统和 n 层架构的示意图。服务器提供了共享的数据模型,客户端与该 数据模型交互。客户端同时还维护数据模型的一部分,以获得快速的访问,但是它将服务器 端的模型当作业务领域对象的最终表示。多个客户端可以与同一个服务器交互,当然,这需 要有合适的资源锁定机制和合理的对象(或者数据行)隔离措施作为保证。服务器可以是单 进程的,就像在 20 世纪 90 年代早期和中期传统的客户/服务器模型中一样,也可以是由很 多个中间件层或者多个 Web 服务等组成。在任何一种情况下,从客户端的角度来看,服务 器都有一个单独的接入点,可以看作是一个黑盒 在现代的 n 层架构中,服务器往往要和更远的后端服务器(例如数据库)通信,因此被称作 “中间件”的层同时扮演着客户端和服务器的角色。我们的 Ajax 应用位于这个链的一端, 它仅仅是作为客户端,因此为讨论方便,我们可以把整个 n 层系统看作是一个标记为“服务 器”的黑盒。 我的电子表格应用只需要管理它自己保存在内存或本地文件系统中的少量数据。如果架构设 计良好的话,数据和它的表现形式的耦合可以非常松散,但是我不能通过网络来分割或者通 过网络来共享它们。从这个意义上来说,电子表格应用不是一个客户端。 与之相对应的 Web 浏览器就是一个典型的客户端,它与 Web 服务器通信,请求需要的页面。 浏览器有丰富的功能,用来管理用户的浏览行为,常见功能有回退按钮、历史列表和分页浏 览多个文档等等。但是当我们把特定网站的 Web 页面看作是一个应用时,这些通用的浏览 功能实际上和应用关系不大,充其量也就如电子表格和 Windows 的开始按钮或者窗口列表 之间的关系。 我们来考察一下现代的 Web 应用。为了简单起见,我们选择了“地球人都知道”的在线书 店 Amazon.com(图 1-4)。在浏览器中打开 Amazon 网站,因为在此之前我访问过,它会给 我显示一个友好的问候、一些推荐书目,还有我的购买历史信息。 点击推荐书目中的任何一条,就会转到另外一个页面(此时,页面要刷新一下,在这几秒钟 内我什么也看不到)。新页面是该书的相关信息:书评、二手书报价、同一作者的其他著作, 以及以前我浏览过的其他书籍(图 1-5)
amazon couk RREE;哪 Your Recommendations Haas,aIpsos tn tea 性国 Boot orignal Flower rer toyear all wih The Glasgow School of Art P的p单包建aHd M 图1-4 Amazon. com的首页。系统记得我上一次的访问。导航链接除了通用模板文件,还有 个性化信息 中中·國06 oK. C Digital Photo Deals s wt 20% off digital cameras h ur Ingalls wilder Garth w lams(straton 盈加 图1-5 Amazon com书籍详细信息的页面。包括一大堆通用信息和个性化信息的超链接。虽 说其中的大量内容和图1-4中的一模一样,但是由于Web浏览器使用基于文档的操作,每 次发送新页面都必须要重新发送这些内容 简而言之,呈现在我面前的是非常丰富的、关联度很高的信息。但是对我而言,交互的方式 就是点击那些超链接,然后填写一些表格。假设我在键盘前面不小心睡着了,第二天才醒来, 如果不刷新页面,我就没法知道《哈里·波特》系列的新书已经出版了,也不能将我的列表 从一个页面带到另一个页面,我要是想同时看到更多一些东西也不行,因为我无法改变页面 上局部内容区域的大小 我似乎是在批评 Amazon的界面,其实并非如此,我只是拿它来做个例子。事实上,在传统 Web开发方式的桎梏下,他们已经做得非常棒了。但是比起电子表格来说,它所用的交互 模型毫无疑问是太有限了 为何现代的Web应用仍然有这么多的局限呢?造成目前的状况有一些合理的技术原因,我 们现在就来考察一下 1.1.2网络延迟
图 1-4 Amazon.com 的首页。系统记得我上一次的访问。导航链接除了通用模板文件,还有 个性化信息 图 1-5 Amazon.com 书籍详细信息的页面。包括一大堆通用信息和个性化信息的超链接。虽 说其中的大量内容和图 1-4 中的一模一样,但是由于 Web 浏览器使用基于文档的操作,每 次发送新页面都必须要重新发送这些内容 简而言之,呈现在我面前的是非常丰富的、关联度很高的信息。但是对我而言,交互的方式 就是点击那些超链接,然后填写一些表格。假设我在键盘前面不小心睡着了,第二天才醒来, 如果不刷新页面,我就没法知道《哈里·波特》系列的新书已经出版了,也不能将我的列表 从一个页面带到另一个页面,我要是想同时看到更多一些东西也不行,因为我无法改变页面 上局部内容区域的大小。 我似乎是在批评 Amazon 的界面,其实并非如此,我只是拿它来做个例子。事实上,在传统 Web 开发方式的桎梏下,他们已经做得非常棒了。但是比起电子表格来说,它所用的交互 模型毫无疑问是太有限了。 为何现代的 Web 应用仍然有这么多的局限呢?造成目前的状况有一些合理的技术原因,我 们现在就来考察一下。 1.1.2 网络延迟
因特网的宏伟蓝图是将这个世界上所有的计算机都连接起来,形成一个无比巨大的计算资 源。如果能把本地调用和远程调用等同起来,那么无论是分析蛋白质的成分还是破解外太空 的信号,使用者都无需考虑机器的物理位置,剩下来的只有愉快地计算。 但是非常不幸,本地调用和远程调用是完全不同的东西。在现有的技术水平之下,网络通信 仍然是一件代价高昂的事情(也就是说,通常很慢,而且并不可靠)。在没有网络调用的情 况中,不同的方法和函数以及它们所操作的数据都位于相同的本地内存中(图1-6),向方 法内传递数据并且获得方法的返回结果是非常直接的。 模型 (本鲍内存 图1-6本地过程调用的顺序图。参与者很少,因为程序逻辑与数 据模型都保存在本地内存中,并且彼此可以直接访问 而在有远程调用的情况下,位于网络两端的通信双方为了发送和接收数据在底层需要进行大 量计算(图1-7)。比起数据在线路上的往返,这些计算需要消耗更多的时间。传输一段二 进制的数据,中间要经过很多环节的编码和解码、错误校验、失败重发、数据包拆分和重组, 数据最终转化为0和1表示的二进制信号,通过线路(或者无线连接)到达另外一方 在本地,调用函数的调用请求被编码为一个对象,然后将这个对象序列化为一系列字节,最 后使用应用层协议(通常是HIP)通过物理传输介质(例如铜缆、光纤或者无线电波)将 其发送出 在远程机器上,对应用层协议解码,将获得的数据字节反序列化,创建一个请求对象的副本 然后对数据模型应用这个对象并生成一个响应对象。为了将响应对象传递给本地的调用函 数,所有的序列化、反序列化以及传输层的操作都要反向再来一次。最后,响应对象被传递 给本地的调用函数。 本炮模型序列化》)感用协议)物理传输应用议序列化远程模型 图1-7远程过程调用的顺序图。一台机器的程序逻辑尝试操作另外一台机器上的数据模型 这个交互过程很复杂吧,幸好,它是可以自动完成的。现代的编程环境如Java和 Microsoft 的NET框架都内置了这个能力。尽管如此,执行远程调用时,上述所有这些操作仍然会在 内部执行。如果我们到处使用远程调用,性能势必会大受影响。 这也就是说,远程调用是不可能和本地调用一样有效率的。更糟糕的是,网络的不稳定更让
因特网的宏伟蓝图是将这个世界上所有的计算机都连接起来,形成一个无比巨大的计算资 源。如果能把本地调用和远程调用等同起来,那么无论是分析蛋白质的成分还是破解外太空 的信号,使用者都无需考虑机器的物理位置,剩下来的只有愉快地计算。 但是非常不幸,本地调用和远程调用是完全不同的东西。在现有的技术水平之下,网络通信 仍然是一件代价高昂的事情(也就是说,通常很慢,而且并不可靠)。在没有网络调用的情 况中,不同的方法和函数以及它们所操作的数据都位于相同的本地内存中(图 1-6),向方 法内传递数据并且获得方法的返回结果是非常直接的。 图 1-6 本地过程调用的顺序图。参与者很少,因为程序逻辑与数 据模型都保存在本地内存中,并且彼此可以直接访问 而在有远程调用的情况下,位于网络两端的通信双方为了发送和接收数据在底层需要进行大 量计算(图 1-7)。比起数据在线路上的往返,这些计算需要消耗更多的时间。传输一段二 进制的数据,中间要经过很多环节的编码和解码、错误校验、失败重发、数据包拆分和重组, 数据最终转化为 0 和 1 表示的二进制信号,通过线路(或者无线连接)到达另外一方。 在本地,调用函数的调用请求被编码为一个对象,然后将这个对象序列化为一系列字节,最 后使用应用层协议(通常是 HTTP)通过物理传输介质(例如铜缆、光纤或者无线电波)将 其发送出去。 在远程机器上,对应用层协议解码,将获得的数据字节反序列化,创建一个请求对象的副本。 然后对数据模型应用这个对象并生成一个响应对象。为了将响应对象传递给本地的调用函 数,所有的序列化、反序列化以及传输层的操作都要反向再来一次。最后,响应对象被传递 给本地的调用函数。 图 1-7 远程过程调用的顺序图。一台机器的程序逻辑尝试操作另外一台机器上的数据模型 这个交互过程很复杂吧,幸好,它是可以自动完成的。现代的编程环境如 Java 和 Microsoft 的.NET 框架都内置了这个能力。尽管如此,执行远程调用时,上述所有这些操作仍然会在 内部执行。如果我们到处使用远程调用,性能势必会大受影响。 这也就是说,远程调用是不可能和本地调用一样有效率的。更糟糕的是,网络的不稳定更让