5 个 Ajax 最佳实践

优化 Ajax 开发的技巧和工具

通过对这 5 个最佳实践的学习,您可将其应用到日常的 Asynchronous JavaScript + XML(Ajax)开发工作中。文章包括了数据格式、错误处理、以及一些采用 Ajax 的 Rich Internet Applications(RIAs)开发工具。掌握这些最佳实践,有助于您编写更加高效且健壮的 Ajax 代码。

Nathan A. Good, 高级顾问,自由开发人员, Enterprise Frameworks

Nathan Good Nathan A. Good 居住在明尼苏达州的双子城。他的专长是软件开发、软件架构和系统管理。平时不编写软件时,他喜欢组装 PC 和服务器、阅读和撰写技术文章,并鼓励他的所有朋友转用开源软件。他是许多书籍和文章的作者或合著者,包括 Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution ApproachFoundations of PEAR: Rapid PHP Development


developerWorks 投稿作者

2011 年 10 月 31 日

本文所介绍的 5 个最佳实践,可以应用到您 web 应用程序 Ajax 开发工作中:

  1. 最小化调用
  2. 让数据变小
  3. 预加载组件
  4. 轻松实现错误处理
  5. 使用现有工具

这些最佳实践,有助于您编写更加健壮的 JavaScript 代码,并使您的 Ajax 代码执行的更快,这可以给用户带来益处。

Ajax 概述

Ajax 用于描述存在已久的技术:JavaScript 代码、XML、以及能够通过 HTTP 进行异步调用的对象。Ajax 常用于避免提交并重新加载整个网页,特别是在用户执行的动作不需要重新加载整个网页时。

在过去几年中,支持 Ajax 的站点在不断的完善,作为此类站点的开发工具,Ajax 的应用也越来越广泛。使用本文的实践通过 Ajax 和 JavaScript 来构建更优的 web 应用程序。


最小化调用

听起来可能很明显,但使用 Ajax 技术提高您的 web 应用程序性能,惟一能做的就是最小化您的调用数量。

最小化调用数量的方法之一是将大量调用合并成少量调用。如果数据量相对小(见 “让数据变小”),那么在大多数网络中,主要问题就在于延迟。延迟是浏览器真正获取服务器与服务的连接所需的时间,有时它会占去大部分连接时间。用户所感受到的总延迟由几个部分组成,包括浏览器的缓存设置、DNS 客户端、以及物理连接。

没有简易公式或代码片段供您阅读来了解如何减小 web 应用程序调用。然而,只需一个简单的练习,就可以演示如何对从客户端到服务器的 Ajax 调用数量进行控制。考虑购买二手摩托车的 web 应用程序(见图 1)。

图 1. 搜索二手摩托车的示例 web 页面
截屏中有构造、型号、年份、以及邮编字段的下拉按钮。

首先,用户选择摩托车的年份。然后,用户选择摩托车的构造。最后用户选择摩托车的型号。从始至终,Ajax 一直在后台运行,更新 web 应用程序中的下拉框来为用户过滤清单,以方便用户选择。

要开始这一练习,首先要为客户端及服务器创建一个简单图表(有一个文本框)。然后为您浏览器进行的 Ajax 调用画线,来从服务器获取用户数据,如图 2 所示。

图 2. 绘制 Ajax 调用
从浏览器及服务器中延伸出虚线,在用于品牌、型号与库存的两个之间采用实线。

可通过将对品牌和型号进行的调用合并到一个调用中,来优化设计。不是对品牌进行一次调用,然后针对型号进行另一次调用,而是对型号进行缓存,这样,当用户选择品牌时,新代码只检索缓存中可用的型号列表。从本地缓存中获取数据要比从服务获取相同数据快得多。回避额外的服务调用,您就可以避免服务调用的延迟。新的通信情况如图 3 所示。

图 3. 合并获取品牌调用与获取型号调用后的 Ajax 调用
从浏览器及服务器中延伸出虚线,其中有两条实线;一个用于品牌及型号,另一个用于库存。

到目前为止,新设计在浏览器与服务器之间的通信中去掉了一个调用。您可利用清单 1 中的代码进一步减少调用数量,其中的一些关键行可用于存储在数组中检索到的数据,供以后查找使用。

清单 1. 在缓存中存储本地数据
var choices = new Array();

function fillChoiceBoxes(year) {

    // see resources for links to dojo toolkit...
    if (dojo.indexOf(choices, year) == -1) {
        // go get the         
    } else {
        // make the ajax call and fill the choices.    
        choices[year] = result; // result of ajax call.
    }

    // calling a function to fill the values...
    fillSelect(dojo.byId('makes'), choices[year]);

}

如果用户在反复考虑两个不同的型号,web 应用程序会使用本地缓存数据,而不是发起附加服务调用。仅缓存静态数据 —— 至少是在用户会话持续阶段。不要因为缓存了不应缓存的数据,而引起一系列问题。

正如本例所展示的,可通过减少客户端与服务器之间的交互次数,以及在可能的情况下缓存数据,来最小化调用。


让您的数组变得很小

为提高数据处理性能,需要让服务器与客户端之间出传输的数据尽量的小。为高效地完成这一任务,必须已经控制了从服务层,到能够指定从服务到客户端的消息类型的部分。

有充足的理由证明,XML 适合作为客户端到服务器的通用消息格式。理由之一是存在足够多的库或者框架,来用于 XML 序列化。

然而,当与 JavaScript Serialized Object Notation(JSON)对比时,XML 显得很冗长,而前者更加简明。目前已经有很多可以将您的消息方便地构建成 JSON 格式的库,这样就可以通过 JSON 的方式将数据从服务端传送的客户端。

很多客户端库,比如 Dojo Toolkit,允许定义服务所采用的传输格式。如果服务响应使用 JSON,可通过提供一个参数来使用相同的客户端对象。

仔细研究一下清单 2 中的代码,其展示了使用 XML 的摩托车对象的表示。

清单 2. 使用 XML 的摩托车数据
<motorcycle>
  <year>2010</year>
  <make>Motocool</make>
  <model>Uberfast</model>
</motorcycle>

现在来看一下清单 3,其展示了使用 JSON 的相同数据。注意,它的代码量减少了大约 25%(如果去掉空格)。

清单 3. 使用 JSON 的摩托车数据
{ 
"motorcycle" : { 
    "year" : "2010", 
    "make" : "Motocool", 
    "model" : "Uberfast"
    }
}

由于数据量变小了,不仅减少了从服务端到客户端的传输时间,而且,由于字符串的减小还节省了解析时间。

在设计需要传输的数据时,其所包含的字符越少越好。


预加载组件

可通过在 Ajax 调用中加载 JavaScript 文件与图像之类的组件,来充分利用浏览器的缓存。需要注意的是,预加载 JavaScript 文件和图像,仅对那些开启缓存功能的用户有益,不过大多数用户的浏览器都开启了缓存功能。

想要预加载外部 JavaScript 文件,将 JavaScript 文件包 面中,但是,只有当该页面很小而且仅想优化少量资源时,才适合采用这一方式。例如,当您有一个将工作流引入用户的相对轻量级的页面时,预加载非常有用。考虑 最小化调用 部分中购买摩托车的例子。可在流的早期页面中预加载用于包含下拉框的页面的、包含全部 Ajax 代码的 JavaScript 代码。

如果要用 Ajax 调用的方法更新图片,预加载图像会提供很大方便。预加载图像后,当用户将鼠标移动到元素时、从下拉框中进行选择时、或者单击按钮时,不必等待浏览器对图像进行检索。即使 Ajax 以异步方式发生,也需要花费一些时间将图像从服务器传送到客户端,并且在图像全部下载完毕之前,它不会在客户端中显示。

在清单 4 所展示的例子中,用户进行从清单中选择摩托车这一操作时,所采用的图像就是使用标准 JavaScript 代码预加载的。

清单 4. 使用标准 JavaScript 代码预加载图像
<html>
<head><title>Preload example</title></head>
<body>
<!-- web page... -->
<script type="text/javascript" language="javascript">
    var img = new Image();
    img.src = "http://path/to/motocool.jpg";
</script>
</body>
</html>

为页面预加载图像时,JavaScript 的位置很重要。您一定不希望因为在 HTML 中加入了 JavaScript 代码而影响页面的加载速度。一般的规则是,可将 <script> 元素当中的 JavaScript 代码放到 HTML 页面的最后部分,因为在考虑可同时下载多少资源时,浏览器的能力就相对有限了。如果可能,将脚本加到 HTML 页面的最后部分,来帮助浏览器更快速加载图像和其他资源。

在 HTML 5 中,可使用 <script> 标记的新 async 属性。这将告诉浏览器异步运行 JavaScript 代码,这样,它可以在页面中运行其他东西时执行。


轻松处理错误

在 JavaScript 代码中定义的每个函数,都要假设会有恶意输入发生,因为,防御性能强的代码比使用 try... catch 语句所编写的代码更善于处理错误。例如,如果想使用 JavaScript 函数来根据用户输入进行计算,在计算前检查输入,如清单 5 所示。

清单 5. 检查用户输入
function caculateDistance(source,dest) {
    if (! isNaN(source) || ! isNan(dest)) {
        dojo.byId("errors").innerHTML = "Please provide a valid number.";
    }
}

即使代码具有防御能力,在适当时候,也可使用 try... catch 语句与错误回调。清单 6 演示了在 JavaScript 代码中使用 try... catch 语句来捕获错误。

清单 6. 使用 try... catch 语句来处理错误
function calculateDistance(source,dest) {
    try {
        // do some calculations...
    } catch (error) {
        dojo.byId("errors").innerHTML = "An error occurred while adding the numbers";
    }
}

清单 7 演示了在调用 Dojo Toolkit 中所提供的 xhrGet() 方法时,对错误回调的使用。错误参数是可选的,因此可以很容易地跳过错误处理器的定义。

清单 7. 使用具有 xhrGet() 的错误回调
var args = {
    url: "/moin_static185/js/dojo/trunk/dojo/../dojo/NoSuchFile",
    handleAs: "text",
    preventCache: true,
    load: function(data) {
        // do something when successful...
    },
    error: function(error) {
        dojo.byId("errors").innerHTML = "An error occurred while getting the data..";
    }
}
var ajx = dojo.xhrGet(args);

如何处理页面上的错误,这既是个业务问题,也是个技术问题。要询问客户,在出现问题时,想让用户看到什么消息,因为任何展示给用户的消息,都会对业务造成影响。适当时,客户能够帮助提供在出现异常时有效的默认处理方式。

最后,不要象清单 8 中那样,在 JavaScript 提示对话框中显示错误描述。您的用户不是软件工程师,因此,这类提示信息对于用户来说没有任何意义。除了不要为用户提供无意义的信息之外,提示对话框应当要求客户取消该对话框,来返回 web 页面。

清单 8. 在错误处理中避免 JavaScript 提示对话框
function calculateDistance(source,dest) {
	try {
		// do some calculations...
	} catch (error) {
                // Bad:
		// alert(error.message);
                // Better:
                dojo.byId("errors").innerHTML = 
                    "An error occurred while calculating data...";
	}
}

使用现有工具

最后,作为最佳实践之一,要尽量避免 Not Invented Here(NIH)综合症。通过使用现有工具(框架与平台),可有效利用其资源。大多数成熟的技术人员,会使用已在多个平台上测试过,并具有跨浏览器兼容性的工具。现有工具的大部分特性可用于部署到您自己的项目中。

很多现有的优秀工具,除了能提供 Ajax 调用之外,还能支持很多其他函数与特性,比如动画。表 1 中列出了其中一些工具。

表 1. 为 Ajax 调用提供方法的 JavaScript 工具
工具描述
Dojo ToolkitDojo Toolkit 是免费的 JavaScript 工具套件。它为一般 web 页面提供 Ajax 调用方法,以及 Representational State Transfer(REST)服务。Dojo Toolkit 方法支持 XML、JSON、以及明文的消息格式。
Google Web Toolkit(GWT)DesignerGoogle 最近收购了 Instantiations Developer Tools 并重新推出一系列免费产品。其中之一是 GWT Designer,可将其安装到现有的 Eclipse 中。可利用设计器来辅助构建采用 GWT 的接口。GWT 用于构建采用 Ajax 的复杂 web 应用程序,这使得 web 应用程序可以如同本地应用程序一样复杂。与 Rich Ajax Platform(RAP)类似,GWT 不单单是一个 JavaScript 框架,而且还是编译到 Ajax-enabled HTML 中的基于 Java™ 的工具集。
jQueryjQuery 是另一个 JavaScript 库,它能提供全套的 Ajax 功能。jQuery 还支持不同的消息格式以及其他基于 Ajax 的方法,比如 getScript(),它可用于下载并执行 JavaScript 文件(是 预载组件 最佳实践的起源)。
PrototypePrototype 也是个 JavaScript 框架,可用于方便地发起 Ajax 调用。利用 Ajax.PeriodicalUpdater 之类的方法,可基于策略来更新 Ajax 页面中的值,这样,就可为运行时间较长的服务进程实现进度条或者其他方式的控制。
Rich Ajax Platform (RAP)

与表中列出的其他框架不同,RAP 是个完整的平台,使得您可以利用 Eclipse 集成开发环境(IDE)和 Java(不是脚本)代码来构建 Ajax-enabled 的更优站点。类似于构建一个 Swing 或者 Standard Widget Toolkit(SWT)应用程序。对于不想使用复杂的 HTML、CSS、以及 JavaScript 代码的 Java 程序员来说,RAP 之类的平台工具是非常不错的选择。

RAP 文档提示说不要将其作为插件安装到现有 Eclipse 中。然而,可从 Eclipse 站点(见 参考资料)下载 Eclipse for Rich Client Platform(RCP)and RAP Developers 包,并将其安装到单独的位置。相关备忘单展示了如果导入示例项目。


结束语

在 web 应用程序中使用 Ajax ,可为您的用户提供整洁的 web 应用程序界面。Ajax 已对整个 HTML 页面的传递提供了一些优化,然而,通过了解本文中描述的最佳实践,可帮助您构建更加优化的 Ajax 应用程序。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=768823
ArticleTitle=5 个 Ajax 最佳实践
publish-date=10312011