在上一篇文章《对程序员的一个Promise(一)》中,分享了一下了ES6中Promise的用法,但是需要浏览器支持Promise。在jQuery中也有Promise,就让我来看看jQuery中的Promise是怎么用的。
jQuery中的Promise
在jQuery中,首先要通过Deferred方法获取到Deferred对象,让我们来打印出来看看它有什么方法。
| var d = $.Deferred(); console.log(d);
|
最后输出如下:
我们可以看到$.Deferred()返回是一个对象(Deferred对象),也有resolve、then、reject等一些我们熟悉的方法,让我们来看看它是怎么用的。
基本用法
| function getPromise1(){ var d = $.Deferred(); setTimeout(() => { console.log('异步1结束'); d.resolve('异步1数据'); }, 200); return d; }
var def = getPromise1(); def.then((data) => { console.log(data); });
|
感觉跟ES6中Promise的用法很相似。我们首先通过$.Deferred()获取到了Deferred对象,然后在异步成功后返回数据,然后在then方法中对异步数据进行处理。
但是跟ES6中不一样的是,异步没有放到Promise的构造函数中,在异步成功后,调用了Deferred对象的resolve方法。then方法处理回调数据还是一样的。
发现问题
既然Deferred对象上有resolve()方法,那么是不是在外部就能够调用resolve()方法就能够修改Promise的状态呢。把上面的代码进行如下改写:
| function getPromise1(){ var d = $.Deferred(); setTimeout(() => { console.log('异步1结束'); d.resolve('异步1数据'); }, 300); return d; } var def = getPromise1(); def.then((data) => { console.log(data); }); def.resolve('外部数据1');
|
输出结果如下:
可以看到我们在函数的外面调用了resolve()方法提前让异步结束并且返回了数据。这样Promise的状态就能够被随意的改变,肯定是不行的。
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
解决问题
将代码进行如下改进,在返回的对象上多加一个promise()方法:
| function getPromise1(){ var d = $.Deferred(); setTimeout(() => { console.log('异步1结束'); d.resolve('异步1数据'); }, 300); return d.promise(); } var def = getPromise1(); def.then((data) => { console.log(data); }); def.resolve('外部数据1');
|
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
输出结果如下:
这时候,如果在函数的外部调用resolve()方法会报错,告诉我们resolve()方法不存在,异步也会“如期”执行完成。如果我们将def对象打印出来看的话会发现并没有resolve()方法。
成功和失败的回调
和ES6中的Promise相似,then也支持接收两个参数,分别是执行成功的回调和执行失败的回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function getPromise1(){ var d = $.Deferred(); setTimeout(() => { var number = Math.round(Math.random()*10); if(number %2 == 0) { d.resolve('成功数据'); } else { d.reject('失败数据'); } }, 300); return d.promise(); }
var def = getPromise1(); def.then( (data) => { console.log('成功回调'); console.log(data); }, (data) => { console.log('失败回调'); console.log(data); } )
|
除此之外,jQuery还新增了两个函数,done()和fail()分别用来指定成功的回调和失败的回调。因此,上面的代码和下面的代码是等价的:
| var def = getPromise1(); def.done((data) => { console.log('成功回调'); console.log(data); }); def.fail((data) => { console.log('失败回调'); console.log(data); });
|
链式调用
既然是Promise,那么then()肯定也支持链式调用的,这边也不在赘述,跟ES6中是一样的用法,不太熟悉的可以戳这边《对程序员的一个Promise(一)》
扩展函数
jQuery中没有all和race方法,但是扩展了一些其他的方法。
always方法
always方法就是不管执行成功或者失败,都会执行的,有点类似ajax的complete方法。
| var def = getPromise1(); def.done((data) => { console.log('成功回调'); console.log(data); }); def.fail((data) => { console.log('失败回调'); console.log(data); }); def.always(() => { console.log('总是执行') })
|
when方法
when方法和ES6中的all方法功能一样,都是并行执行异步,所有异步执行完成后才执行回调函数。不过when方法是挂载在全局中的方法,而且,它接受的参数也是多个对象。
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
| function getPromise1(){ var d = $.Deferred(); setTimeout(() => { d.resolve('成功数据1'); }, 100); return d.promise(); } function getPromise2(){ var d = $.Deferred(); setTimeout(() => { d.resolve('成功数据2'); }, 200); return d.promise(); } function getPromise3(){ var d = $.Deferred(); setTimeout(() => { d.resolve('成功数据3'); }, 300); return d.promise(); } $.when(getPromise1(), getPromise2(), getPromise3()) .then((data1,data2,data3) => { console.log('执行完成'); console.log(data1, data2, data3); })
|
理解ajax的本质
平时我们都是这么请求ajax异步的:
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
| $.ajax({ url:'test.json', success:function(data){ }, error:function(data){ } });
|
上面的代码,平时的工作中我们肯定也写了无数遍了,已经很熟悉了,但是这个ajax()方法返回的是什么呢,让我们打印出来看下:
难道是巧合么?我们看到了熟悉的always()、done()、fail()、promise()、then()等方法。没错,ajax返回的也是一个Deferred对象,既然是Deferred对象,那么肯定也支持链式调用了。
那么将ajax方法进行如下改写:
| function getAjax1(){ var def = $.ajax({url:'test.json'}); return def.promise(); } var def1 = getAjax1(); def1.then((data) => { console.log(data); });
|
既然是Deferred对象,那么done()、fail()、$.when()这些方法也能使用,这里就不再赘述了。