借助Ajax自动保存JSF表单之二

创建和发送 Ajax 请求

submitFormData() 函数的代码可以在 AutoSaveScript.js 文件中找到,该函数使用 Ajax 请求对象向 Web 服务器提交编码后的数据。首先,它需要创建这个请求对象,如果是 Microsoft® Internet Explorer,就使用 ActiveXObject(),如果是支持 Ajax 的其他浏览器,比如 Firefox、Netscape、Mozilla、Opera 和 Safari,就使用 XMLHttpRequest()。下面显示了创建 XMLHttpRequest 对象所需的代码。

创建 Ajax 请求对象

function submitFormData(form) {
var xhr;
if (window.ActiveXObject)
xhr = new ActiveXObject("Microsoft.XMLHTTP");
else if (window.XMLHttpRequest)
xhr = new XMLHttpRequest();
else
return null;
...
}

编码后的表单数据被提交给由表单的 action URL 所识别的页面,使用的是特定的 HTTP method,在 JSF 表单的情况下,此方法即为 POST。submitFormData() 函数也可以同非 JSF 表单一起使用,这类表单有可能会使用默认的 GET 方法或 POST。即使这个表单没有指定 action URL,此代码仍可以工作。在这种情况下,submitFormData() 将会使用由 document.URL 获得的当前页面的 URL。编码后的表单数据可通过 getFormData() 函数从 form 对象检索到,该函数在前面已介绍过。如果此 HTTP 方法是 GET,那么编码后的数据会追加到 URL 字符后面。之后,submitFormData() 通过 open() 方法初始化 xhr 对象。

初始化 Ajax 请求对象

function submitFormData(form) {
...
var method = form.method ? form.method.toUpperCase() : "GET";
var action = form.action ? form.action : document.URL;
var data = getFormData(form);

var url = action;
if (data && method == "GET")
url += "?" + data;
xhr.open(method, url, true);
...
}

当从服务器收到对 Ajax 请求的响应时,会调用称为 submitCallback() 的内部函数。如果 autoSaveDebug 的值为 true,这个 Ajax 回调就会发出错误信号,请求虽完成(readyState 为 4),但其状态却不对(status 不是 200)。一旦发生错误,系统就会通过 alert() 报告 xhr 对象的 status 和 statusText 属性,而且 autoSaveDebug 标记也会设为 false 以防您一次又一次地收到错误消息(因为表单保存是周期性执行的)。如果重新加载此页面,JavaScript 代码就会重新初始化,若导致 HTTP 错误的问题仍没有得到解决,您将会再次看到错误消息。这个功能非常适合开发阶段的调试之用。在实际的生产环境中,当发生错误时,与显示告警信息相比,最好是将用户重新引导到其他页面。不管何种情况,xhr 对象的onreadystatechange 属性都必须包含一个对 submitCallback() 的引用以便此回调函数在 Ajax 请求的生命周期中能被调用。

回调函数

var autoSaveDebug = true;

function submitFormData(form) {
...
function submitCallback() {
if (autoSaveDebug && xhr.readyState == 4
&& xhr.status != 200) {
autoSaveDebug = false;
alert("Auto-Save Error: "
+ xhr.status + " " + xhr.statusText);
}
}
xhr.onreadystatechange = submitCallback;
...
}

接下来,submitFormData() 设定 Ajax-Request 报头,它对示例应用程序是特定的,用来在服务器端识别 Ajax 请求,这将在本文后面的部分进行介绍。如果 HTTP 方法是 POST,那么 submitFormData() 函数会设置标准 Content-Type 报头并且会使用 xhr 对象的 send() 方法将表单数据提交给 JSF 页面。如果HTTP 方法是 GET(当前未被 JSF 表单使用),那么表单数据应该已经追加到此 URL,并会用 null 参数调用send()。在提交表单数据后,此函数返回一个对 xhr 对象的引用。

发送 Ajax 请求

function submitFormData(form) {
...
xhr.setRequestHeader("Ajax-Request", "Auto-Save");
if (method == "POST") {
xhr.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xhr.send(data);
} else
xhr.send(null);

return xhr;
}

管理 XHR 实例

当需要重复发送表单数据时,您很可能会倾向于重用 XMLHttpRequest (XHR) 对象,但在多数情况下,这并不是一个好主意,原因很多。首先,它将使代码变得复杂,因为您将不得不进行池的管理,也不得不跟踪 XHR 实例的生命周期。请记住,这些对象的状态通常是在 HTTP 请求完成后存取的,并且在不再需要任何 XHR 时,应用程序代码必须要告知管理该池的代码。此外,一些浏览器在为多重请求而重用 XHR 对象时可能也会存在问题。

为每个 HTTP 请求创建一个新的 XHR 对象也有问题,因为只要应用程序需要这些对象,浏览器就不会从内存中删除它们。如果应用程序不使用 JavaScript delete 操作符释放由 XHR 对象占用的内存,不断发送 Ajax 请求的 Web 页面就可能会导致 Web 浏览器中的内存泄漏。在这种情况下,如果在合理的时间段内没有得到响应,不妨采用一种有效策略:中止请求然后重新发送。服务器和客户机都必须做好获得不规范的 Ajax 请求和响应的准备,有些请求或响应甚至可能会丢失。如果这种方法行不通,可以使用XMLHttpRequest 发送同步请求。

应用程序可以使用 Ajax 实现自动保存,但前提是表单应提供传统的提交按钮或使用同步请求发送数据以做处理。异步请求的不可靠性对于自动保存来说还是可以接受的,因为实现自动保存的作用只是在浏览器瘫痪或网络故障时进行部分恢复。

AutoSaveScript.js 文件包含一个函数,称为 submitAllForms(),它发送此 Web 页面所有表单的数据。这些 XHR 对象保存在一个数组内,数组为每个表单分配一个数组元素。在用 submitFormData() 发送表单数据前,submitAllForms() 函数会中止并删除前面那个自动保存表单曾使用过的请求。在成功完成了的请求上调用 abort() 不起任何作用,并且仅当浏览器收到一个对旧请求的延时响应的情况下,onreadystatechange 才被设置为一个空函数。下面的代码显示了对页面表单进行迭代的代码,以将表单数据提交给服务器。

提交当前页面的所有表单

var autoSaveXHR = new Array(document.forms.length);

function submitAllForms() {
var formArray = document.forms;
for (var i = 0; i < formArray.length; i++) {
if (autoSaveXHR[i]) {
var oldXHR = autoSaveXHR[i];
oldXHR.onreadystatechange = function() { };
oldXHR.abort();
delete oldXHR;
}
autoSaveXHR[i] = submitFormData(formArray[i]);
}
}

由 submitFormData() 返回的 XHR 对象将在下一次调用 submitAllForms() 时删除。AutoSaveScript.js 文件中的另一个函数是 setAutoSaving(),它能使用JavaScript API 的 setInterval() 函数启用表单的自动保存功能。每隔指定的毫秒数,浏览器都会调用 submitAllForms(),直到 setAutoSaving() 被再次使用以借助 clearInterval() 清除之前调用的影响。

启动当前页面的表单自动保存功能

var autoSaveIntervalId = null;

function setAutoSaving(millisec) {
if (autoSaveIntervalId) {
clearInterval(autoSaveIntervalId);
autoSaveIntervalId = null;
}
if (millisec != 0)
autoSaveIntervalId = setInterval(
"submitAllForms()", millisec);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值