开发者社区> 问答> 正文

如何使用$.ajax()返回的deferred对象

1.5版本后的jquery使用$.ajax()返回的是deferred对象
大家都知道deferred对象是jquery给出的回调函数的解决方案
ajax请求可以写成以下形式

$.ajax('target.html')
.done(function(){})
.fail(function(){});

非常简单明了
但现在情况是返回数据中有一字段规定请求失败与否(不是通信问题的错误)

一般jquery的ajax的使用如下(当然是我比较晚知道这个deferred这个对象,可能大家老早就不这样写了)

$.ajax({
    url: target.html,
    success: function(){},
    error: function(){}
});

改写如下

var IO = {};
IO.prototype.ajaxGet = function(url, params, cb, error) {
    $.ajax({
        url: url,
        type: 'get',
        data: params,
        success: function(data) {
            data = $.parseJSON(data);
            if(data.state != 10000) {
                error && error(data);
                return false;
            }
            cb && cb(data);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            //这里是出现请求失败等问题的处理
        }
    });
}

因为与后台约定好当返回state字段值不为10000则算是错误情况
需要到error函数中执行
但是在success与error中要如何获取deferred对象来进行改写
使之可以像本题最上面的写法使用

IO.ajaxGet('target.html', data)
.done(function(data){})
.fail(function(data){});

展开
收起
小旋风柴进 2016-03-25 14:58:07 2392 0
1 条回答
写回答
取消 提交回答
  • 不,你不能在 success/error 回调中获取 deferred 对象的结果(或者说你已经在它的结果中了),这是因为 deferred 对象包含的是“未来”的结果——在你获取 deferred 对象的时候,它所代表的异步请求还没发生。并且正因为如此,我们才能利用 deferred 对象来去定义未来可能发生的事情,要么 success(resolved),要么 error(rejected)。所以在 success/error 回调中获取 deferred 对象是没有意义的,就好像“在未来中获取代表未来的那个过去对象”。

    那么要怎么做?

    从大的层面上来讲,API 的设计不够完整。你们可以自定义错误代码/错误信息,但更重要的是如果发生了错误,那就应该同时修改 HTTP 状态码。我记得 jQuery 的 Ajax 请求会拦截非 2xx 的 HTTP 响应,然后走 error 回调,因此如果你们这样做了,那么属于错误的部分就应该在 deferred.fail() 里面去处理。这才是正途。

    当然现实总是很傻缺,错误也经常以 200 的形式返回给客户端,所以我们不得不在 success 回调中处理异常。那么使用 deferred 的时候怎么做呢?

    deferred 这种模式和 Promise 很像,它也是一个 thenable 对象,它的 then 方法可以让你串联多个函数并依次执行。所以你可以写一个通用的过滤函数来处理返回错误对象的情况,然后 reject 整个 deferred 对象。由于我很久没用 jQuery 了,以下示例代码仅凭印象写下,你就当是伪代码,看个意思就好:

    var deferred = $.ajax({
        url: url,
        type: 'get',
        data: params,
        ...
    });
    
    function processError(response) {
        if (!(response.state == 10000)) {
            // reject deferred 对象,并将状态码传给 .fail() 的回调
            return deferred.reject(response.state);
        }
    
        deferred.resolve(response);    // 这一句可能不需要,细节记不清了
    }
    
    deferred
        .then(processError)            // 调用上面的函数,过滤异步请求的结果
        .done(processYourBussiness)    // 处理正常逻辑
        .fail(errorHandler);           // 处理异常逻辑

    你可能会想不要 errorHandler 转而直接在 processError 里处理异常,但是记住我们之所以这么做,其实就是在“模拟”正确的模式,用 processError 来代替本来应该发生的 HTTP Status 不等于 2xx 的情形。这样一来,无论 API 那里是否处理正确,客户端总是走在正确的轨道上,将来若是 API 更改,处理了正确的状态码,那就只需要去掉 processError 编好,它相当于一个中间件。

    若有可能,还是用 Promise 吧,jQuery 的 deferred 实现是有缺陷的。

    2019-07-17 19:14:24
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载