jquery.Deferred promise解决异步回调

我们先来看一下编写AJAX编码经常遇到的几个问题:

1.由于AJAX是异步的,所有依赖AJAX返回结果的代码必需写在AJAX回调函数中。这就不可避免地形成了嵌套,ajax等异步操作越多,嵌套层次就会越深,代码可读性就会越差。

$.ajax({
    url: url,
    data: dataObject,
    success: function(){
    console.log("I depend on ajax result.");
    },
    error: function(){}
});  

console.log("I will print before ajax finished.");  

2.如果AJAX请求之间存在依赖关系,我们的代码就会形成Pyramid of Doom(金字塔厄运)。比如我们要完成这样一件事:有4个供Ajax访问的url地址,需要先Ajax访问第1个,在第1个访问完成后,用拿到的返回数据作为参数再访问第2个,第2个访问完成后再第3个...以此到4个全部访问完成。按照这样的写法,似乎会变成这样:

$.ajax({
    url: url1,
    success: function(data){
        $.ajax({
            url: url2,
            data: data,
            success: function(data){
                $.ajax({
                    //...
                });
            }
        });
    }
});  

3.考虑这种场景,假如我们同时发送两个Ajax请求,然后要在两个请求都成功返回后再做一件接下来的事,想一想如果只按前面的方式在各自的调用位置去附加回调,这是不是很困难?

可以看到:JavaScript中类似于AJAX这种异步的操作,会导致代码嵌套层次复杂,可读性差,有的时候甚至是实现需求都非常困难。为了解决这种异步回调难的问题,CommonJS组织制定了异步模式编程规范Promises/A。目前该规范已经有了很多的实现者,比如Q, when.js, jQuery.Deffered()等。我们以jQuery.Deffered学习下Promise。

Promise的状态

Promise对象有3种可能的状态:肯定状态(resolved)、否定状态(rejected)、等待状态(pending)。刚开始创建的Promise对象处于pending状态,只能从pending变成resolved或者是从pending变成rejected状态。

var df1 = $.Deferred();
console.log(df1.state());//pending  

var df2 = $.Deferred();
df2.resolve();//resolved
console.log(df2.state());  

var df3 = $.Deferred();
df3.reject();
console.log(df3.state());//rejected  

$.Deferred()创建一个延迟对象(也就是Promise对象),deferred.state()可以获取Promise对象当前所处的状态。deferred.resolve()和deferred.reject()则是用来改变Promise对象的状态。

Promise添加回调函数

Promise对象有3种状态,我们可以分别为这3种状态注册回调函数。当Promise处于某个状态的时候,会触发这个状态下注册的回调函数。

var df = $.Deferred();
df.done(function(){alert("success");});
df.fail(function(){alert("fail");});
df.progress(function(){alert("progress");});  

df.notify();  

df.resolve();
// df.reject();  

done()、fail()、progress()分别注册resolved、rejected、pending状态下的回调函数。通过resolve()、reject()、notify()可以触发事先注册的回调函数。

Promise是支持链式调用的,上面的代码可以写成下面的样子。

var df = $.Deferred();
df.done(function(){alert("success");})
.fail(function(){alert("fail");})
.progress(function(){alert("progress");});  

Promise支持多个回调函数,会按照注册顺序调用。

var df = $.Deferred();
df.done(function(){alert("first");})
.fail(function(){alert("fail");});  

df.done(function(){alert("second");});
df.done(function(){alert("third");});  

df.resolve();  

deferred.always()添加的回调函数,无论Promise是resolved状态还是rejected状态,都会被调用。

var df1 = $.Deferred();
df1.always(function(type){alert(type);});
df1.resolve("resolve");  

var df2 = $.Deferred();
df2.always(function(type){alert(type);});
df2.reject("reject");  

progress()和notify()能够用来实现进度条效果,因为notify()允许调用多次,而reject()和resolve()只能调用一次。这个很好理解,因为一旦状态变成resolved或者是rejected,就不能再改变其状态,也没有必要。

var df = $.Deferred();
df.done(function(){alert("success");});
df.fail(function(){alert("fail");});
df.progress(function(){alert("progress");});    

// resolve()调用2次,但是只能触发1次success
df.resolve();
df.resolve();    

var mudf = $.Deferred();
mudf.done(function(){alert("success");});
mudf.fail(function(){alert("fail");});
mudf.progress(function(){alert("progress");});    

// 每次调用notify都会触发progress回调函数
mudf.notify("%10");
mudf.notify("%20");    

rejectWith()、resolveWith()、notifyWith()功能上和reject()、resolve()、notify()没有什么差别,主要差别在于回调函数中的执行上下文(方法中的this)和参数形式。具体差别可以参考"JQuery.Callbacks系列一:api使用

// 老的ajax写法
$.ajax({
  url: "test.html",
  success: function(){
    alert("success");
  },
  error:function(){
    alert("error");
  }
});  

// 使用promise后的写法
$.ajax("test.html")
 .done(function(){})
 .fail(function(){})
 .done(function(){)
 .fail(function(){);  

JQuery中的Deferred对象与Promise对象区别

JQuery.Deferred相关的API,有的返回的是Deferred对象,有的返回的是Promise对象。如done()、reject()等大部分函数返回的都是Deferred对象,$.when()和then()函数返回的是Promise对象。具体可以参考JQuery API文档。

JQuery官方对Promise Objects的解释是:

This object provides a subset of the methods of the Deferred object (then, done, fail, always, progress, state and promise) to prevent users from changing the state of the Deferred.

可以看到Promise对象其实就是Deferred对象的一部分,Deferred对象提供了notify、reject、resolve等改变状态的方法,但是Promise对象没有提供这些方法。

文章开始提到的AJAX问题1~3,问题1可以很容易通过Promise得到解决。问题2和问题3是通过$.when()和deferred.then()得到解决,由于这2个API相对来说复杂一些,以后的文章再分析这2个API。

详解"这篇文章中的fire()和fireWith()。

上面简单的介绍了Promise的使用方式,我们可以用Promise的方式来编写AJAX代码。可以很容易地看出:使用Promise后代码嵌套层次少了,代码是纵向增长的,而不再是横向增长。而且使用Promise,可以指定多个ajax回调函数。

jquery Deferred 快速解决异步回调的问题

function ok(name){

  var dfd = new $.Deferred();
  callback:func(){

     return dfd.resolve( response );
  }

  return dfd.promise();
}

$.when(ok(1),ok(2)).then(function(resp1,resp2){})

//相关API 分成3类

1类:$.when(pro1,pro1) 将多个 promise 对象以and的关系 合并为1个

2类:promise 激发为 解决 deferred.resolve([ args ] ) deferred.resolveWith( context, [ args ] )

和 拒绝 .reject  .rejectWith

context 上下文 替换 this 和通知 .notify  .notifyWith

3类: 对激发的响应  解决时deferred.done(args) 拒绝时 deferred.fail() 通知时 deferred.progress()

不管 解决 或 拒绝 deferred.always()

deferred.then( doneCallbacks, failCallbacks [, progressCallbacks] )

promise(或者叫deferred 延迟对象如何获取?)

var dfd = new $.Deferred(); return dfd.promise();

返回promise当前状态

deferred.state()  pending(尚未完成) resolved rejected

管道

deferred.pipe( [ doneFilter ], [ failFilter ] ) 

var defer = $.Deferred()

var filtered = defer.pipe( null, function( value ) {

   return value * 3;
});

defer.reject( 6 );
filtered.fail(function( value ) {
   alert( "Value is ( 3*6 = ) 18: " + value );
});
时间: 2024-10-21 17:41:09

jquery.Deferred promise解决异步回调的相关文章

js中promise解决callback回调地狱以及使用async+await异步处理的方法

1.callback回调地狱 function ajax(fn) { setTimeout(()=> { console.log('你好') fn() }, 1000) } ajax(() => { console.log('执行结束') ajax(()=>{ console.log('执行结束') ajax(()=>{ console.log('执行结束') ajax(()=>{ console.log('执行结束') }) }) }) }) 2.promise解决回调地狱

promise解决异步嵌套问题

function a(){ return new Promise(function(res,rej){ $.ajax({ url:"a", type: "GET", async:true, dataType:"json", success:function(data){ console.log(data,"a"); res(data); } }) }); } function b(data){ console.log(data

解决异步回调方法中,初始化Cef时WPF界面卡死的问题

Application.Current.Dispatcher.BeginInvoke(new Action(() =>                            { })); 注意用Invoke同样会卡死,只能用BeginInvoke

jquery deferred小结

jquery deferred是一个异步回调的机制 目前,jQuery的Ajax方法($.ajax,$get,$post)返回的都是Promise对象. 异步回调的适合作用于i/o事件,要等待用户动作才能做出相应的callback. 比如,传递promise对象就相当于声明:“你感兴趣的某某事就要发生了,想知道什么时候完事吗?给这个promise一个回调就行了!“ promise对象和EventEmitter对象一样,允许向同一个事件绑定任意多的处理器(堆积技术) 如$('#doucment')

Promise对象和回调函数,解决异步数据传递问题

下面的代码例子,均已小程序的异步请求数据为案例来说明 1.利用回调函数,来解决异步数据传递问题 1 异步操作api.js 2 const getBooks = (url, callback) => { 3 wx.request({ 4 url: url, 5 method: 'GET', 6 header: { 7 "Content-Type": "json" 8 }, 9 success: function (res) { 10 console.log(re

async + promise 解决回调地狱

// 解决异步回调地狱的方案: async + promise async function writeFile() { // 打开文件 const fd = await new Promise((resolve, reject) => { // 执行 打开文件 异步操作 fs.open('c.txt', 'w', (err) => { if (!err) { // 将promise对象的状态改成 成功状态 resolve(); } else { // 将promise对象的状态改成 失败状态

js异步回调Async/Await与Promise区别 新学习使用Async/Await

Promise,我们了解到promise是ES6为解决异步回调而生,避免出现这种回调地狱,那么为何又需要Async/Await呢?你是不是和我一样对Async/Await感兴趣以及想知道如何使用,下面一起来看看这篇文章:Async/Await替代Promise的6个理由. 什么是Async/Await? async/await是写异步代码的新方式,以前的方法有回调函数和Promise. async/await是基于Promise实现的,它不能用于普通的回调函数. async/await与Prom

JS魔法堂:jQuery.Deferred(jQuery1.5-2.1)源码剖析

一.前言 jQuery.Deferred作为1.5的新特性出现在jQuery上,而jQuery.ajax函数也做了相应的调整.因此我们能如下的使用xhr请求调用,并实现事件处理函数晚绑定. var promise = $.getJSON('dummy.js') // 其他逻辑处理 promise.then(function(){ alert('late binding') }) 我还一度以为这就是Promises/A+规范的实现,但其实jQuery.Deferred应该与jsDeferred归为

jQuery源码研究分析学习笔记-jQuery.deferred()(12)

JS是单线程语言,把每一件事情(包括GUI事件和渲染)都放在一个线程里来处理是一个很好的程序模型,因为这样就无需再考虑线程同步这些复杂问题. 但js暴露了应用开发中的一个严重问题,单线程环境看起来对用户请求响应迅速,但是当线程忙于处理其它事情时,就不能对用户的鼠标点击和键盘操作做出响应. jQuery.deferred异步模型提供了一个抽象的非阻塞的解决方案. jQuery.deferred()在jQ中常用的有: promise Ajax模块 动画模块 DOM ready jQuery.Defe