您的位置:首页 > Web前端 > JavaScript

充分利用异步回调(JavaScript 应用程序中实现数据源协调)

2007-12-30 14:52 302 查看
在 JavaScript 应用程序中实现数据源协调





文档选项


打印本页



将此页作为电子邮件发送



英文原文

级别: 中级

David Mertz (mertz@gnosis.cx), Impatient data source, Gnosis Software, Inc.

2007 年 12 月 28 日

要在 JavaScript 应用程序中充分利用 Ajax 数据源的异步回调,需要使用一些技巧。本文将讨论针对 Ajax 数据源使用异步回调的原因,并将通过一些示例演示如何协调彼此相关的应用程序数据源,使这些数据源在任何时间内都能进行异步调用。
简介

异步数据源中存在的问题就是:它们不是同步的。尤其是,通过 HTTP 协议请求传递的数据可能会远远晚于预期到达,或者请求发生超时,或者完全失败。任何 TCP 层协议都具有不可靠性,但是 Ajax 应用程序可能与多个服务器有数据依赖关系,而这些服务器将影响到整个 Web 应用程序。

处理数据依赖关系并非 Ajax 应用程序的特别之处。各种各样的应用程序都使用信号量、队列、共享变量等在进程中与状态进行通信;在本例中,进程 通常指的是数据获取请求。但是,Web 应用程序中的超时和其他服务器或网络问题多于大多数其他类别的应用程序(尤其是与严格执行本地运行的应用程序相比)。此外,在数据源(甚至同一数据源中的多个请求)中的时序变化方面,基于 Web 的应用程序也要高于大多数其他类型的应用程序,甚至要高于使用基于网络的资源(如数据库)的多数应用程序。








回页首
请求状态和超时

我们将遇到的大多数代码示例都是关于异步 Ajax 使用
XMLHttpRequest()
检查是否接收到
200 OK
状态码。我建议在检查的内容中添加一些其他可行的状态,以及一个用于表示完全超时的 “伪状态”。我在近期的一篇 developerWorks 技巧 “使用会话状态避免不必要的 Ajax 流量”(参见 参考资料 获得文章链接)中,我提供了一个利用
304 状态码
的示例,该示例仍然是个不错的想法。

适当处理各种 HTTP 状态码是个不错的想法。针对 2xx 状态码(而不是
200 OK
)的操作仍然有点悬而未决:比如说,如果应用程序将创建一个服务器资源,那么您可能希望检查
201 Created
状态码并查看响应中的 URI。标准情况下,客户机必须 透明的重定向状态码 301、302、303 和 307。因此,我们实际上不必担心它们,因为它们最终将得到 200 状态(或者是超时、4xx 和 5xx 状态)。区别处理 4xx 错误和 5xx 错误可能是一个很好的方法。概括地说,4xx 状态码(尤其是常见的
404 Not Found
错误)可能表示客户机所使用 URL 中存在一些问题。5xx 错误表示服务器存在问题,通常只需等待一段时间并重试便可解决该问题。

与处理各种服务器错误同样重要的情况是,有时服务器会无限期挂起,而根本不会返回任何响应。挂起实质上等同于 5xx 状态码,不同之处就是我们无法检查
XMLHttpRequest().status
状态码来识别它们。为此,我们可以使用一个
setTimeout()
计时器来取消超时请求。

将相关检查结合在一起,我们的 Ajax 数据源请求可能类似于清单 1:

清单 1. 数据源请求的健壮处理

function getResource(uri, data_callback, error_callback, timeout) {
var tryAgain = function () {
getResource(uri, data_callback, error_callback, timeout);
}
var r = new XMLHttpRequest();
var timer = setTimeout(
function() {
r.abort();
r.onreadystatechange = null;
setTimeout(tryAgain, timeout);
},
timeout);
r.open("GET", uri, true);
r.onreadystatechange = function() {
if (r.readyState != 4) {
// Ignore non-loaded readyStates
// ...will timeout if do not get to "Loaded"
return;
}
clearTimeout(timer);  // readyState==4, no more timer
if (r.status==200) {  // "OK status"
data_callback(r.responseText);
}
else if (r.status==304) {
// "Not Modified": No change to display
}
else if (r.status >= 400 && r.status < 500) {
// Client error, probably bad URI
error_callback(r)
}
else if (r.status >= 500 && r.status < 600) {
// Server error, try again after delay
setTimeout(tryAgain, timeout);
}
else {
error_callback(r);
}
}
r.send(null);
return r;
}

当然,我们可以在
getResource()
中加入各种增强。比如说,在超时或服务器错误状态事件中,我们可以在延时之后调用
tryAgain()
。或者,我们可能希望在这两种情况下使用一些其他的回调。传递的
error_callback()
函数将用于下面这种情况,即不希望再次发送重复请求,但是常常会发生这种情况。








回页首
数据协调

给出的
getResource()
函数可能会无限制地等待,获取数据源并将其提供给
data_callback()
。但是,该数据回调自己可能需要依赖其他数据的可用性。同时操作多个数据源的最简单方法就是将它们的内容存储在一个全局变量中,并当该数据被使用时清空这些变量。比如说,基本的回调方法可能类似于清单 2:

清单 2. 两个源的基本数据回调

var other_data = null;
function processOtherData(responseText) {
other_data = responseText;
}
function processData(this_data) {
var delay = 1000;     // Keep trying at 1-second intervals
if (other_data == null) {
setTimeout(function() { processData(this_data); }, delay);
return;
}
// We have both this_data and other_data
displayThisAndThat(this_data, other_data);
// Reset other_data now that we have consumed it
other_data = null;
}

应用程序将调用
getResource(uri1,processOtherData,...)
方法,然后将在别处调用
getResource(uri2,processData,...)
方法。后面这个调用将运行一个回调从内部 “轮询”
other_data
直到它实际填入了数据,并在该数据被处理后将它清空。另一个信号量可能与以下操作相关,避免重复后面这个调用,直到第一次尝试成功并且/或针对延时的
processData()
调用
clearTimeout()
,有利于更新的请求。








回页首
结束语

数据协调的具体应用在任何种类的应用程序中的复杂度都会有所不同 — 而不仅仅是 Ajax 应用程序。本文所提供的示例只使用一个主数据表示函数
processData()
和一个有用的回调来获取额外的数据,即
processOtherData()
。但是,这种模式非常容易应用到广泛的相互依存的数据源。


developerWorks Ajax 资源中心
访问 Ajax 资源中心,其中提供了关于开发 Ajax 应用程序的各种免费工具、代码和信息。由 Ajax 专家 Jack Herrington 管理的 动态 Ajax 社区论坛 为 Ajax 开发人员提供了相互交流和解决问题的平台。
在任何情况下,
getResource()
函数都是一个很好的通用框架,它可用于解决在 HTTP 上获取数据时遇到的问题。通常,该访问最终都会成功,前提是在表达请求时没有发生客户端错误。也就是说,短暂的网络和服务器错误只意味着延时,而不是故障。当然,在 Ajax 应用程序中,我们需要使用一些特别的技巧来从多个域中获取数据。其方法通常是将
XMLHttpRequest()
对象放置在单独隐藏的 IFrames 中以轮询不同的域,不过这对异步协调毫无特别之处。

参考资料

学习

您可以参阅本文在 developerWorks 全球站点上的 英文原文

W3C 在 RFC2616 中正式给出了 HTTP 状态码的定义

请阅读我的上一篇 Ajax 技巧文章:"技巧:使用会话状态避免不必要的 Ajax 通信量。"

developerWorks Ajax 资源中心 提供了各类工具、代码和信息,可帮助您立刻开始开发灵活的 Ajax 应用程序。

随着 Web 2.0 成为热门开发领域,您可以从 Web 开发专区 找到各类资料。

讨论

MochiKit 库拥有一个相当不错的异步框架,可用于推迟任何函数的调用,而并不仅限于等待
XMLHttpRequest()
对象。但是对于该技巧,我们只关心数据请求,而不是长时间运行的计算。了解 MochiKit.Async

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: