Ajax 引擎一个有趣的特征就是:尽管它包含了很多应用程序逻辑和表示框架元素,但是如果经过恰当的设计,它可以不包含任何业务数据或个性化内容。应用程序和表示都冻结在部署时。在典型的 Web 环境中,应用程序资源可能 6 个月才会变更一次。这意味着负责隔离应用程序资源和数据资源的 Ajax 引擎是高度可缓存的。
Dojo Toolkit 就是一个很好的例子(请参看 参考资料)。Dojo 提供了构建时工具来创建一个包含所有应用程序逻辑、表示和风格的压缩 JavaScript 文件。由于它终究只是一个文件,因此 Web 浏览器可以对其进行缓存,这意味着我们第二次访问启用 Dojo 的 Web 应用程序时,很可能就会从浏览器缓存中加载 Ajax,而不是从服务器上加载它。我们可以将这种情况与高度融入化的服务器端 Web 应用程序进行一下对比,后者每次请求都会导致大量的服务器处理,因为浏览器和网络中介不能对缓存不断变化的资源。
由于 Ajax 应用程序引擎只是一个文件,因此它也是可以使用代理缓存的。在大型的企业内部网中,只要有一名员工曾经下载过某个特定版本的应用程序的 Ajax 引擎,其他任何人都可以从内部网网关上上获取一个缓存过的拷贝。
因此对于应用程序资源来说,经过良好定义的 Ajax 应用程序引擎符合 REST 准则,与服务器端 Web 应用程序相比,它具有显著的可伸缩性优势。
缓存 Ajax 数据
用户浏览一个 Ajax Web 站点,加载 Ajax 应用程序引擎,最好是从浏览器缓存中加载的,否则就从本地代理服务器加载。那么对于业务数据来说情况如何呢?由于应用程序逻辑和状态都在浏览器上驻留并执行,因此应用程序与服务器的交互就与传统 Web 应用程序的方式有很大的不同。不需要获取混合的内容页面,只需要获取业务数据即可。
现在回到 Amazon.com 的例子上来,假设我们点击了一个链接,要查看有关设计模式的一本书籍。在 Amazon.com 目前的应用程序中,链接点击操作会发送很多标识所请求的资源的信息。它还会发送很多会话状态信息,这让服务器可以创建一个新页面,其中可以包括之前的状态(例如最近查看的内容)、个性化信息(例如您在 1999 年购买的书籍)以及实际的业务资源本身。应用程序是动态且高度个性化的 —— 但是却不能缓存,也无法伸缩(正如 Amazon 所示范的一样,这些架构问题都可以通过投入大量资金构建基础设施来克服)。现在我们考虑一下这个操作在(假想的)Ajax 版本的应用程序中的情况。对于 “最近查看的内容” 并不需要进行处理。当我们点击某个链接时,这些在页面上已经存在的信息并不会消失。有两个请求很可能会与设计模式的书籍有关:
第一个假定的请求会返回有关书籍的信息(作者、标题、简介等);其中并没有包含特定于用户的数据。特定于用户的数据意味着当更多用户请求相同的资源时,很可能会从 Internet 上的中间节点上来检索缓存版本,而不是从原始服务器上检索这些资源。这种特性会降低服务器和总体网络负载。另外一方面,第二个请求包含了特定于用户的信息(Bill Higgins 的购买该书的历史记录)。由于这些数据包括一些个性化信息,因此只有一名用户需要从这个 URI 中获取并缓存数据。尽管这种个性化数据并没有非个性化数据的可伸缩特性,但是重要的问题是这些信息都是直接从 URL 中获取的,因此都具有这样的正面特征:它们都不会妨碍其他可缓存的应用程序和数据资源的缓存。
Ajax 和健壮性
Ajax 架构风格的另外一个优点是它可以轻松处理服务器的故障。正如我们前面介绍的一样,具有融入式用户体验的服务器端 Web 应用程序通常会在服务器上保存大量的用户会话状态。如果服务器发生了故障,会话状态就丢失了,那么用户就会体验到非常奇怪的浏览器行为(“为什么我又回到主页上来了?我的购物车中的东西都到哪里去了?”)。在采用有状态客户机和无状态服务的 Ajax 应用程序中,服务器崩溃/重新启动对于用户来说都是完全透明的,因为服务器崩溃不会影响会话状态,这些都保存在用户的浏览器中;无状态服务的行为是幂等的,可以由用户请求的内容来单独确定。
承诺和问题对于我们称为融入式 Web 应用程序的那些 Web 应用程序来说,设计良好的 Ajax/REST 应用程序在用户体验、响应性和可伸缩性方面都远远超过传统的服务器端 Web 应用程序。然而,一种架构风格的运行时特征对于软件项目和 Web 应用程序来说并非是决定成功的惟一因素。在创建 Ajax/REST 应用程序时有一些非常困难的非运行时问题,包括大规模 JavaScript 开发、文化问题和打包问题。我们将在另外一篇文章中讨论有关文化的问题,其他内容留待我那些研究 Ajax 的同僚们去处理。