jquery deferred promise

js有一种设计模式”订阅/发布者”模式,或者叫”观察者模式”,jquery实现观察者模式就是用deferred。

/** * 定义一个主题 */
var subject = function(){
   var def = $.Deferred();
   setTimeout(function(){
       def.resolve("发布主题"); //发布一个主题
   },3000); 
   return def ;
}

/** 1. 观察者 */
var obs1 = function(msg){
   console.log(msg); //输出:
}
$.when(subject()).done(obs1); //订阅主题

defferred有三种状态,解决resolve ,失败reject,进度notify,内部实现使用jquery的callback对象的三种组合形式

jQuery.Callbacks( "once memory" );//resolve
jQuery.Callbacks( "once memory" ); //reject
jQuery.Callbacks( "memory" );//notify

对应的处理函数是done,fail,progress。

  1. 处理成功
var subject = function(){
   var def = $.Deferred();
   setTimeout(function(){
       def.resolve("success"); //改变def的状态为成功
   },3000); 
   return def ;
}
$.when(subject()).done(function(msg){//处理成功回调
   console.log(msg);
}); 
  1. 处理失败
var subject = function(){
   var def = $.Deferred();
   setTimeout(function(){
       def.reject("fail"); //改变def的状态为失败
   },3000); 
   return def ;
}
$.when(subject()).fail(function(msg){//处理失败回调
   console.log(msg);
}); 

3.处理进度

var subject = function(){
   var def = $.Deferred();
   setTimeout(function(){
       def.notify("notify"); //发布一个进度通知
   },3000); 
   return def ;
}
$.when(subject()).progress(function(msg){//处理进度
   console.log(msg);
}); 

deferred支持链式调用,如果你觉得麻烦,可以直接这样子写

$.when(subject()).done(function(msg){}).fail(function(msg){}).progress(function(msg){}); 

或许你觉得三个函数要分开写,很麻烦,那你可以这样

$.when(subject()).then(sucssfn,failfn,progressfn);

再或者你觉得三种状态不用分开写,那就这样吧

$.when(subject()).always(function(def){ //所有状态的通知都会在这个回调里面
   var state = def.state();
   switch(state){  //处理状态
      case "pending" : //处理中
       ...
      break ;
      case "resolved" : //处理成功
       ...
      break ;
      case "rejected" : //处理失败
       ...
      break ;
   } 
});

用$.when()可以绑定多个函数到队列中,等所有函数执行万再回调

$.when(fn1,fn2,fn3).then(..);

细心的读者有没有发现,我们把$.Deffered写在subject函数作为局部变量,并已经修改了状态,返回了一个def对象到外部,有没有可能外部函数会改变def的状态呢,例如这样

var subject = function(){
   var def = $.Deferred();
   setTimeout(function(){
       def.done("success"); //发布一个进度通知
   },3000); 
   return def ;
}

var su = subject();
su.reject("fail");  //在函数外部修改了defferred的状态
$.when(subject()).done(function(){msg}).fail(function(){msg}); //发现调用的是fail的函数,而不是最初的done函数,违背初衷

为了解决这个问题,jquery推出promise对象,$.promise(),when和then函数都是返回promise对像,由于promise对象没有resolve,reject和notify方法,故不能改变defferred的状态。所以上面可以这样子来改

var subject = function(){
   var def = $.Deferred();
   setTimeout(function(){
       def.done("success"); //发布一个进度通知
   },3000); 
   return def.promise() ; //返回promise对象,不能改变def对象状态
}

$.when(subject()).done(function(){msg}); 

.promise对象用来观察当某种类型的所有行动绑定到集合,排队与否还是已经完成,它有俩个参数,.promise(type,target),type是回调的类型,默认是”fx”,即表示绑定到集合里面的动作必须等所有的动画执行完成之后才会触发回调,若提供target,.promise()将附加到它的方法,然后返回这个对象,而不是创建一个新的。这对在已经存在的对象上附加Promise的行为非常有用。看下官网的例子:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>promise demo</title>
  <style> div { height: 50px; width: 50px; float: left; margin-right: 10px; display: none; background-color: #090; } </style>
  <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>

<button>Go</button>
<p>Ready...</p>
<div></div>
<div></div>
<div></div>
<div></div>

<script> $( "button" ).on( "click", function() { $( "p" ).append( "Started..." ); $( "div" ).each(function( i ) { $( this ).fadeIn().fadeOut( 1000 * ( i + 1 ) ); }); $( "div" ).promise().done(function() { //所有div动画执行完之后回调 $( "p" ).append( " Finished! " ); }); }); </script>

</body>
</html>

关于defferred和promise就记录到这里

你可能感兴趣的:(jquery,Promise,观察者,deferred,state)