之前用angular的$http向接口发起请求,里面的回调写法感觉很好看,最近用jquery,也找到相同的写法,展示于此处。
jq Ajax中的Promise
常规的ajax
写法:
1 2 3 4 5 6 7 8 9 10 11 12 13
| $.ajax({ type : "post", dataType : "json", url : "project_getProJect.action", async : true, data:{proUuid:uuid}, success : function(result) { }, error: function(error){ }, complete: function(){ } });
|
为了方便使用ajax
,封装如下:
1 2 3 4 5 6 7 8
| function AjaxServer(url,data){ return $.ajax({ type:'POST', url:url, data:data, dataType:'json' }); }
|
那么,这个AjaxServer
返回的是什么呢?是一个XMLHttpRequest
(jqXHR
)对象,从jQuery1.5开始,该对象实现了Promise
接口, 使它拥有了 Promise
的所有属性、方法和行为。可参考:jQuery.Deferred对象
然后就可以这样调用ajax:
写法1
1 2 3 4 5 6 7 8 9 10
| AjaxServer(url,data).done(function(data, textStatus, jqXHR){ }).fail(function(jqXHR, textStatus, errorThrown){ }).always(function(data|jqXHR, textStatus, jqXHR|errorThrown){
})
|
写法2
1 2 3 4 5
| AjaxServer(url,data).then(function(data, textStatus, jqXHR) { }, function(jqXHR, textStatus, errorThrown) { });
|
从angular沿袭下来的习惯,我比较喜欢写法2。
Tip:在调用接口失败时或者接口返回的值不是我们期望的值时,我们经常需要提示,但这两种情况的提示一般是相近的(如果要求不严格的话),所以为了简练,可以这样写:
1 2 3 4 5 6 7
| AjaxServer(url,data).always(function(result,textStatus,obj){ if(result.data&&result.data==true){
}else{ } });
|
对比参考:angular中promise与defer
基本用法:强制同步(以点击事件触发为例)
html:
1 2 3 4 5 6 7
| <input type="text" value="小明" id="name"> <input type="button" value="查询" onclick="search()"> <br><br> <input type="button" value="点击" onclick="click1()" class="bt" id="click1"> <input type="button" value="点击" onclick="click2()" class="bt"> <input type="button" value="点击" onclick="click3()" class="bt"> <input type="button" value="点击" onclick="click4()" class="bt">
|
js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function search(){ delegateClick().done(function(result){ console.log('search:'+result); }) } var defer; function delegateClick(){ defer=$.Deferred(); $('.bt').click(); return defer.promise(); }
function click1(){ console.log('1'); } function click2(){ console.log('2'); } function click3(){ console.log('3'); } function click4(){ setTimeout(function(){ console.log('模拟ajax的延迟'); defer.resolve('click4执行完了'); },2000); }
|
点击”查询”按钮的输出结果为:
从结果可以看出:resolve()
触发了done(callback)
。其实:
- defer.resolve():触发 done 的回调执行,并传值给回调方法。
- defer.reject():触发 fail 的回调,并传值给回调方法。
- defer.notify():触发 progress 的回调,并传值给回调方法。
另外:上面这三个方法都会触发 always 的回调
链式调用
有这样三个方法,让他们链式调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function delay(){ var defer=$.Deferred(); setTimeout(function(){ console.log('delay()'); defer.resolve(); },2000); return defer.promise(); } function animate(){ return $('#name').animate({height:'100px'},1000,function(){ console.log('动画执行完成'); }).promise(); } function click1(){ var defer=$.Deferred(); setTimeout(function(){ console.log('click1()'); defer.resolve(); },500); return defer.promise(); }
|
写法1
1 2 3 4 5 6 7 8 9 10 11 12
| function search(){ var promiseA=delay(); var promiseB=promiseA.then(function(){ return animate(); }); var promiseC=promiseB.then(function(){ return click1(); }); promiseC.then(function(){ console.log('链式调用完成'); }); }
|
结果如图:
写法2
1 2 3 4 5 6 7
| function search(){ $.when(delay()).then(animate).then(click1).then(function(){ console.log('链式调用完成'); }) }
|
结果同写法1
$.when()
接受一个Promise对象,$.when更多介绍
如果写作:
1
| $.when(delay()).then(animate()).then(click1());
|
那就相当于
1
| $.when(delay(),animate(),click1());
|
其结果是:三个方法异步一起执行。
备注:promise与defer的区别
promise:promise 对象是没有 resolve , reject , notify 等方法的,也就意味着,你无法针对 promise 对象进行状态更改,只能在 done 或 fail 中进行回调配置。promise相当于defer对象的子集。