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

//看到这个问题马上打开家里的windows去拖了个sublime来怒答

先谈理想,哦不,概念

首先defered模式不是伪promise,而是promise的一个变种。promise的初版Promise/A只有一个必备API then,后来的Promise/B已经具备了defer方法,虽然jQuery的实现细节与其不同,但基本意图是一样的(可以将promise的resolve这件事同样以方法调用的形式解决)

Promise是一个复杂的大家族,jQuery虽然曾经离经叛道,但自从pipe方法被舍弃,归并入then之后,已经是一个相当完整的Promise实现了。并不100%,但如果不考虑一些特殊场景(后详)下,jQuery的实现已经是Promise/A的超集。

再谈实际情况

Ajax业务错误是最最典型的超级适合用Promise解决问题的场景了,因为Promise的then方法有改变promise状态的能力,也就是标准的这句话

The value returned from the callback handler is the fulfillment value for the returned promise.

在更准确一些的Promise A+中,相应的描述也更明确易懂

then must return a promise [3.3].

promise2 = promise1.then(onFulfilled, onRejected);

If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).

If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.

If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.

If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

换句人话,哦不,中文来说,想要改变promise的对象的状态,只要在then的参数回调当中返回相应的值,普通值代表成功,throw代表失败,另一个promise代表透传

jQuery的实现和标准略有区别,首先throw不会改变promise为失败而是直接就throw出去了,然后在失败的分支里返回非promise的值X的时候,最终promise的状态不是【成功,值X】而是【失败,值X】

重新换句人话,就是jQuery里想要扭转promise的状态就只能依靠返回另一种状态的promise对象。

上实际代码

jsfunction ajaxGet(url, params) {

return $.get(url, params)

.then(function(response) {

var obj;

try {

obj = $.parseJSON(response);

} catch(e) {

return reject({

state: 123,//比如说123代表返回结果非json

response: response,

error: e

});

}

if(obj.state !== 10000) {

return reject(obj);//直接把整个响应丢出去,如果约定了错误格式,可以在这里整理一下msg之类

}

return response;//成功! 如果约定了成功格式,也可以在这里转换

}, function(xhr) {//这是答主擅自追加的特性,可以不要

//网络错误

return reject({

state: 456,//比如说456代表网络错误

xhr: xhr//这是jqXHR对象,里面有错误详情

});

});

}

function reject(reason) {//构造处在错误状态的promise对象

var dfr = $.Deferred();

dfr.reject(reason);

return dfr.promise();

}

答主的习惯是在这个封装里顺便再给后台一个特殊的状态,比如state===789代表跳转,然后if(obj.state===789) window.location=obj.url;这样,顺便搞定了ajax捅出去以后发现未登录时跳转登录页等等各种需求,都是业务代码不用管的。另外会统一把错误整理成一句话放在比如msg字段里面, 很多时候业务可以在错误的时候直接.fail(function(err) {alert(err.msg || '未知错误')})完事儿

怒答了好久……

最后如果还意犹未尽的同学,不妨看看这几个issue,描述了三年前,chai-as-promise的作者和jquery中相关模块的作者及其他小伙伴们相爱相杀的曲折经历

最后的结局是喜闻乐见的一个困难的决定

if (typeof assertion._obj.pipe === "function") {

throw new TypeError("Chai as Promised is incompatible with jQuery's so-called “promises.” Sorry!");

}

幸运的是至少把pipe改名为then这一点还是顺利合入了jQuery1.7,这样看来事情还是一个不错的结局。否则SegmentFault今天还会多100个『jQuery pipe then和Promise的关系』之类的问题,github上还会多很多让jQuery更像Promise的第三方库,甚至连 Promise还能不能进入ES的草案都成疑问

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值