javascript - 当成功函数失败时,jQuery Ajax promise 队列不起作用

标签 javascript jquery ajax promise

我有一个单页应用程序,它使用基于 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 请求。

我需要做什么来解决这个问题?

最佳答案

由于 jQuery 的 $.ajax 返回一个 promise (并且由于您正在使用它),请放弃使用 success 回调。而是在 then 回调中移动该代码。这将允许您链接一个 catch 方法 (jQuery 3.x) 调用它来响应错误。如果您没有在该 catch 回调中触发另一个错误,则它返回的 promise 将再次得到解析(而不是拒绝),因此链的其余部分不会被中止:

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 2.x

以上需要 jQuery 3.x。在 3.x 之前的 jQuery 版本中,您可以像这样替换 catch 方法(注意 null 参数):

       ...
    }).then(null, function (err) {
       ...

...但 jQuery 2.x 的 promise 并非如此 Promise/A+合规性,这使得正确处理变得很痛苦。以下是如何为 jQuery 2.x 做到这一点。此代码段使用模拟延迟和 HTTP 响应状态代码的 URL,这允许它测试请求错误、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 初始化为立即解决的 Promise,您可以避免代码重复:

var appAjaxPromise = $.when();    
function ajaxRequestQueue(someAjaxData, functionToCallBack, someCallBackData) {
    appAjaxPromise = appAjaxPromise.then(function () {
        return ajaxSender(someAjaxData, functionToCallBack, someCallBackData);
    });
    return appAjaxPromise;
}

关于javascript - 当成功函数失败时,jQuery Ajax promise 队列不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45536328/

相关文章:

javascript - 如何访问对象键中有空格的 JavaScript 对象?

尽可能使用 CSS 实现 jQuery UI 平滑过渡

Javascript 代码仅在页面刷新后有效,而不是首次查看

jquery - 如何在jquery中选中/取消选中复选框时执行事件

jquery - 类更改后在 jQuery 中重新计算元素高度

javascript - 如何使用 AJAX 基于数据库中的值创建动态复选框?

asp.net - 在学习 Ajax 之前我应该​​学习 Xml 和 Javascript 吗?

php - load() 函数添加的内容在 ajax 操作后消失

javascript - 循环根据键获取对象的值

javascript - 无限滚动交替