1.5版本后的jquery使用$.ajax()返回的是deferred对象
大家都知道deferred对象是jquery给出的回调函数的解决方案
ajax请求可以写成以下形式
JavaScript
$.ajax('target.html') .done(function(){}) .fail(function(){});
非常简单明了
但现在情况是返回数据中有一字段规定请求失败与否(不是通信问题的错误)
一般jquery的ajax的使用如下(当然是我比较晚知道这个deferred这个对象,可能大家老早就不这样写了)
javascript
$.ajax({ url: target.html, success: function(){}, error: function(){} });
改写如下
JavaScript
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
对象来进行改写
使之可以像本题最上面的写法使用
如
JavaScript
IO.ajaxGet('target.html', data) .done(function(data){}) .fail(function(data){});
不,你不能在
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 了,以下示例代码仅凭印象写下,你就当是伪代码,看个意思就好:你可能会想不要
errorHandler
转而直接在processError
里处理异常,但是记住我们之所以这么做,其实就是在“模拟”正确的模式,用processError
来代替本来应该发生的 HTTP Status 不等于 2xx 的情形。这样一来,无论 API 那里是否处理正确,客户端总是走在正确的轨道上,将来若是 API 更改,处理了正确的状态码,那就只需要去掉processError
编好,它相当于一个中间件。若有可能,还是用 Promise 吧,jQuery 的
deferred
实现是有缺陷的。