我有一个单页应用程序,它使用基于promise的排队机制,如下所示:
a)处理ajax请求的函数
function AjaxSender(SomeAjaxData, FunctionToCallBack, SomeCallBackData) {
return $.ajax({
url: ...,
type: "POST",
data: SomeAjaxData,
success: function (msg, textStatus, request) {
if (FunctionToCallBack) {
FunctionToCallBack(SomeCallBackData);
//problem if there's a bug when this executes
}
}
});
}
b)使用promise对象对请求进行排队的函数
var AppAjaxPromise;
function AjaxRequestQueue(SomeAjaxData, FunctionToCallBack, SomeCallBackData) {
if (AppAjaxPromise) {
AppAjaxPromise = AppAjaxPromise.then(function () {
return AjaxSender(SomeAjaxData, FunctionToCallBack, SomeCallBackData);
});
return AppAjaxPromise;
}
AppAjaxPromise = AjaxSender(SomeAjaxData, FunctionToCallBack, SomeCallBackData);
return AppAjaxPromise;
}
当我想发送ajax请求时,我调用AjaxRequestQueue(TheAjaxData, TheFunctionToCallBack, TheCallBackData)
并且排队机制确保如果同时发送多个请求,或者在一个请求完成返回之前,它们排队并在前一个请求之后处理一个完成。
当错误停止执行回调函数时,会出现问题。如果该函数出错,则整个排队机制停止,并且调用AjaxRequestQueue不再触发ajax请求。
我需要做些什么来解决这个问题?
答案 0 :(得分:4)
当jQuery的$.ajax
返回一个promise(并且因为你正在使用它)时,放弃使用success
回调。而是在then
回调中移动该代码。这将允许您链接catch
方法(jQuery 3.x)调用它以响应错误。如果你没有在catch
回调中触发另一个错误,它返回的承诺将再次被解决(不被拒绝),因此你的链的其余部分不会被中止:
function ajaxSender(someAjaxData, functionToCallBack, someCallBackData) {
return $.ajax({
url: ...,
type: "POST",
data: someAjaxData
}).then(function (msg, textStatus, request) {
if (functionToCallBack) {
functionToCallBack(someCallBackData);
}
}).catch(function (err) {
console.log('error occurred, but request queue will not be interrupted', err);
});
}
以上需要jQuery 3.x.在3.x之前的jQuery版本中,您可以像这样替换catch
方法(注意null
参数):
...
}).then(null, function (err) {
...
...但是jQuery 2.x承诺不符合Promise/A+,这使得纠正它变得很痛苦。以下是如何为jQuery 2.x执行此操作。此代码段使用模仿延迟的URL和HTTP响应状态代码,这样可以测试请求错误,JavaScript运行时错误和排序:
function ajaxSender(someAjaxData, functionToCallBack, someCallBackData) {
return $.ajax({
// URL for demo: server will use the sleep parameter in the data,
// and will return the given HTTP status
url: "http://httpstat.us/" + someAjaxData.status,
type: "GET", // The demo URL needs a GET
data: someAjaxData
}).then(function (data) {
if (functionToCallBack) {
try { // Would not be necessary if jQuery 2.x were Promise/A+ compliant
functionToCallBack(someCallBackData);
} catch (e) {
console.log(someCallBackData, 'Error occurred during callback');
}
}
}, function (err) { // This second function captures ajax errors
console.log(someCallBackData, 'HTTP error');
// Return a resolved promise.
// This would not be necessary if jQuery 2.x were Promise/A+ compliant
return $.when();
}); // In jQuery 3.x you would chain a catch call here instead of the try/catch.
}
var appAjaxPromise = $.when();
function ajaxRequestQueue(someAjaxData, functionToCallBack, someCallBackData) {
appAjaxPromise = appAjaxPromise.then(function () {
return ajaxSender(someAjaxData, functionToCallBack, someCallBackData);
});
return appAjaxPromise;
}
// Demo: the ajax data argument is also used to define the HTTP response status and
// the sleep time, and the data argument identifies the number of the call
// Survive an HTTP error
ajaxRequestQueue({ status: 404, sleep: 1000 }, myCallBack, 1);
// Survive a runtime error in the callback
ajaxRequestQueue({ status: 200, sleep: 2000 }, myErrorGeneratingCallBack, 2);
// Demo that the callback calls remain in the right order
ajaxRequestQueue({ status: 200, sleep: 3000 }, myCallBack, 3);
ajaxRequestQueue({ status: 200, sleep: 2000 }, myCallBack, 4);
ajaxRequestQueue({ status: 200, sleep: 1000 }, myCallBack, 5);
function myCallBack(data) {
console.log(data, "My callback is called");
}
function myErrorGeneratingCallBack(data) {
console.log(data, "My callback is called");
throw "I threw an error in my callback";
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
移动到jQuery 3时,您仍然可以继续上述模式:它仍然有效。但理想情况下,您应该将代码迁移到我在顶部提供的基于catch
的版本。
只有当变量是构造函数/类时,才能将变量的第一个字母大写一致。
通过将appAjaxPromise
初始化为立即解决的承诺,您可以避免重复代码:
var appAjaxPromise = $.when();
function ajaxRequestQueue(someAjaxData, functionToCallBack, someCallBackData) {
appAjaxPromise = appAjaxPromise.then(function () {
return ajaxSender(someAjaxData, functionToCallBack, someCallBackData);
});
return appAjaxPromise;
}
答案 1 :(得分:0)
我不确定这个答案是否会解决它,但是你在成功函数中使用的回调可能无法从那里访问。
您可以像这样向请求中添加额外的数据......并且可以使用&#39; this ....&#39;来访问它。 (见成功)。
不确定你是否应该使用ether:p我一直这样做是为了从对象内部传递数据而不必更改ajax&#39;上下文或使用$ .proxy。此外,我还能够从请求的成功内部访问一个触发请求的对象函数,使其以块的形式发送文件时递归。
如果对此有任何意见,我很乐意听到。
return $.ajax({
FunctionToCallBack: FunctionToCallBack,
SomeCallBackData: SomeCallBackData,
url: ...,
type: "POST",
data: SomeAjaxData,
success: function (msg, textStatus, request) {
if (this.FunctionToCallBack) {
this.FunctionToCallBack(this.SomeCallBackData);
//problem if there's a bug when this executes
}
}
});