Promise 到 jQuey的Deferred

作者 johansen 日期 2017-04-20
Promise 到 jQuey的Deferred

这周来一次实战,延续上周的promise的介绍,谈谈工作中我们一直在使用JQuery,对于JQuery来说deferred就是jQuery的回调函数解决方案。
当今,我们遇到异步操作,常常引入回调函数,今天我们不谈ajax的回调函数。我们仅谈一下关于通过deferred的状态改变来进行后续逻辑操作。

首先我们先创建一个Deferred对象。下文基本都用这个对象进行说明。

1
var deferred = $.Deferred();


deferred.resolve() && deferred.reject()

jQuery规定,deferred对象有三种执行状态—-未完成,已完成和已失败。如果执行状态是”已完成”(resolved),deferred对象立刻调用done()方法指定的回调函数;如果执行状态是”已失败”,调用fail()方法指定的回调函数;如果执行状态是”未完成”,则继续等待,或者调用progress()方法指定的回调函数jQuery1.7+版本API

我们看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
var dtd = $.Deferred(); // 新建一个Deferred对象
  var wait = function(dtd){
    var tasks = function(){
      alert("执行完毕!");
      dtd.reject(); // 改变Deferred对象的执行状态
    };
    setTimeout(tasks,5000);
    return dtd;
  };
  $.when(wait(dtd))
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

我们通过手动改变dtd的状态,完成相关操作(done或者fail)。但是这样写并不好,我们暴露了dtd对象,因此接下来引入deferred.promise()方法。

deferred.promise()

我们通过deferred.promise()屏蔽改变执行状态有关的方法(比如resolve()方法和reject()方法),从而使得执行状态不能被改变。deferred.promise(),是在原来的deferred对象上返回另一个deferred对象。
例证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var dtd = $.Deferred(); // 新建一个Deferred对象
  var wait = function(dtd){
    var tasks = function(){
      alert("执行完毕!");
      dtd.resolve(); // 改变Deferred对象的执行状态
    };
    setTimeout(tasks,5000);
    return dtd.promise(); // 返回deffer对象
  };
  var d = wait(dtd); // 新建一个d对象,改为对这个对象进行操作
  $.when(d)
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });
  d.resolve(); // 此时,这个语句是无效的

建议还是将dtd作为内部调用,不对外。

另一种防止执行状态被外部改变的方法,是使用deferred对象的建构函数$.Deferred()。这时,wait函数还是保持不变,我们直接把它传入$.Deferred(),jQuery规定,$.Deferred()可以接受一个函数名(注意,是函数名)作为参数,$.Deferred()所生成的deferred对象将作为这个函数的默认参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var wait = function(dtd){
    var tasks = function(){
      alert("执行完毕!");
      dtd.resolve(); // 改变Deferred对象的执行状态
    };
    setTimeout(tasks,5000);
    return dtd.promise();
  };
  $.Deferred(wait)
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

综上我们介绍了相关JQuery的Deferred,希望今后多用到生产实践中,回顾三周的Promise的学习,发现技术的革新不断吸取好的实践,成为提案进而作为新的标准,所以温故知新的考量一个知识点的演变,真的大有裨益,历史是这样的,技术的变化未尝不是呢。

后天周末了,还是要炫耀一下上周我竟然骑行110公里,把北京郊外的十三陵全部刷了一遍,成就感爆棚。周末快乐哈。