Deferred对象

摘要:虽然js已经出了ES6,ES7等等版本,从而也诞生了新的异步对象->promise,但是基础还是要终结的,这一片就来回顾一下ajax以及ajax的异步对象->deferred。

1.传统ajax

传统模式$.ajax()接受参数为一个对象,该对象包含了callback(success和error)

栗子:

 1 function toJson(data) {
 2     document.write('<pre><code>' + JSON.stringify(data) + '</code></pre>');
 3 }
 4 $.ajax({
 5     url: "http://yapi.demo.qunar.com/mock/10343/getinfo",
 6     success: function (data) {
 7         toJson(data);
 8     },
 9     error: function (error) {
10         console.log('error');
11     }
12 });

这里安利一个第三方平台YAPI,可以通过YAPI模拟server端。

运行结果:

2.随着jQuery的改进,新的写法诞生了

栗子:

 1 function toJson(data) {
 2     document.write('<pre><code>' + JSON.stringify(data) + '</code></pre>');
 3 }
 4 $.ajax("http://yapi.demo.qunar.com/mock/10343/getinfo")
 5 .done(function(data){
 6     toJson(data);
 7 })
 8 .fail(function(e){
 9     console.log(e);
10 })

运行结果:

增加了链式用法。这是为啥呢。因为jQuery在1.5.0版本以后增加了deferred对象,支持了链式调用方式。

3.增加了多个延迟函数公用一个回调函数,于是$.when()诞生了。

栗子:

 1 function toJson(arr) {
 2     arr.forEach(a => {
 3         document.write('<pre><code>' + JSON.stringify(a) + '</code></pre>');
 4     })
 5 }
 6 $.when($.ajax("http://yapi.demo.qunar.com/mock/10343/getinfo"),
 7     $.ajax("http://yapi.demo.qunar.com/mock/10343/getinfo"))
 8     .done(function (data, data2) {
 9         toJson([data[0], data2[0]]);
10     })
11     .fail(function (e) {
12         console.log(e);
13     })

结果:

这里如果两个ajax如果其中有一个失败则会调用fail的callback,到这里如果异步不是ajax呢,是setTimeout呢~

栗子:

1 function wait() {
2     var delayFn = function () {
3         console.log('over.');
4     };
5     setTimeout(delayFn, 5000);
6 };

要知道执行函数wait的时候,delayFn会以一个新的宏任务从新扔到一个事件队列里,这时两个函数变成为了异步,那么这时候出现一个新的函数,如何控制新的函数要执行与延迟函数之后呢。

方式1:讲函数写在延迟函数内,这不废话吗。

方式2:如果与wait在同属一个宏任务呢?答案是利用$.when(),以微任务的形式存在。这样等延迟函数执行完再去执行,就是我们上面栗子3的形式了。

栗子:

 1 function wait(dtd) {
 2     console.log(new Date())
 3     var delayFn = function () {
 4     };
 5     setTimeout(delayFn, 5000);
 6 };
 7 $.when(wait())
 8     .done(function (data) {
 9         console.log(new Date());
10     })
11     .fail(function (e) {
12         console.log(e)
13     })

执行结果:

事实上并没有等延迟函数执行完,才进入的回调函数,似乎直接就执行了回调函数,这是为啥呢?

原因是:$.when()接受的对象必须是deferred对象,否则会立即执行回调函数。改进如下。

栗子:

 1 var dtd = $.Deferred();
 2 function wait(dtd) {
 3     console.log(new Date())
 4     var delayFn = function () {
 5         dtd.resolve();
 6     };
 7     setTimeout(delayFn, 5000);
 8     return dtd;
 9 };
10 $.when(wait(dtd))
11     .done(function (data) {
12         console.log(new Date());
13     })
14     .fail(function (e) {
15         console.log(e)
16     })

运行结果:

deferred对象此外还有两个方法分别是:reject()、promise()

resolve:改变deferred对象的状态,执行done callback。

reject:reject()与reslove()方法一样,同为改变deferred对象的状态,当状态为reject时,这执行fail callback。

promise:重新生成deferred对象。

4.promise对象

我猜ES6也是根据这个词儿诞生的promise对象,嘿嘿。

上面栗子可以看到dtd是外部传入的对象,在wait以外就可以改变deferred对象状态,直接执行回调函数

栗子:

 1 function toJson(arr) {
 2     arr.forEach(a => {
 3         document.write('<pre><code>' + JSON.stringify(a) + '</code></pre>');
 4     })
 5 }
 6 var dtd = $.Deferred();
 7 function wait(dtd) {
 8     console.log(new Date())
 9     var delayFn = function () {
10         dtd.resolve();
11     };
12     setTimeout(delayFn, 5000);
13     return dtd;
14 };
15 $.when(wait(dtd))
16     .done(function (data) {
17         console.log(new Date());
18     })
19     .fail(function (e) {
20         console.log('error' + ' time:' + new Date())
21     })
22 dtd.reject();

执行结果:

可以看到在外面修改deferred状态就会立即执行fail callback函数了。那么如何避免呢~,我们利用promise() 重新生成一个deferred对象。

 栗子:

 1 function toJson(arr) {
 2     arr.forEach(a => {
 3         document.write('<pre><code>' + JSON.stringify(a) + '</code></pre>');
 4     })
 5 }
 6 var dtd = $.Deferred();
 7 var waitDtd = function wait(dtd) {
 8     console.log(new Date())
 9     var delayFn = function () {
10         dtd.resolve();
11     };
12     setTimeout(delayFn, 5000);
13     return dtd.promise();
14 };
15 $.when(waitDtd)
16     .done(function (data) {
17         console.log(new Date());
18     })
19     .fail(function (e) {
20         console.log('error' + ' time:' + new Date())
21     })
22 waitDtd.reject();

over~

 

posted @ 2019-02-22 16:04  漠然0408丶  阅读(159)  评论(0编辑  收藏  举报