前两篇我们讲了ES6中的Promise以及Promise/A+规范,在Promise的知识体系中,jquery当然是必不可少的一环,所以本篇就来讲讲jquery中的Promise,也就是我们所知道的Deferred对象。
事实上,在此之前网上有很多文章在讲jquery Deferred对象了,但是总喜欢把ajax和Deferred混在一起讲,容易把人搞混。when、done、promise、success、error、fail、then、resolve、reject、always这么多方法不能揉在一起讲,需要把他们捋一捋,哪些是Deferred对象的方法,哪些是ajax的语法糖,我们需要心知肚明。
先讲$.Deferred
jquery用$.Deferred实现了Promise规范,$.Deferred是个什么玩意呢?还是老方法,打印出来看看,先有个直观印象:
输出如下:
1 2 |
var def = $.Deferred(); console.log(def); |
输出如下:
$.Deferred()返回一个对象,我们可以称之为Deferred对象,上面挂着一些熟悉的方法如:done、fail、then等。jquery就是用这个Deferred对象来注册异步操作的回调函数,修改并传递异步操作的状态。
Deferred对象的基本用法如下,为了不与ajax混淆,我们依旧举setTimeout的例子:
在runAsync函数中,我们首先定义了一个def对象,然后进行一个延时操作,在2秒后调用def.resolve(),最后把def作为函数的返回。调用runAsync的时候将返回def对象,然后我们就可以.then来执行回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 |
function runAsync(){ var def = $.Deferred(); //做一些异步操作 setTimeout(function(){ console.log('执行完成'); def.resolve('随便什么数据'); }, 2000); return def; } runAsync().then(function(data){ console.log(data) }); |
在runAsync函数中,我们首先定义了一个def对象,然后进行一个延时操作,在2秒后调用def.resolve(),最后把def作为函数的返回。调用runAsync的时候将返回def对象,然后我们就可以.then来执行回调函数。
是不是感觉和ES6的Promise很像呢?我们来回忆一下第一篇中ES6的例子:
区别在何处一看便知。由于jquery的def对象本身就有resolve方法,所以我们在创建def对象的时候并未像ES6这样传入了一个函数参数,是空的。在后面可以直接def.resolve()这样调用。
1 2 3 4 5 6 7 8 9 10 11 |
function runAsync(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('执行完成'); resolve('随便什么数据'); }, 2000); }); return p; } runAsync() |
区别在何处一看便知。由于jquery的def对象本身就有resolve方法,所以我们在创建def对象的时候并未像ES6这样传入了一个函数参数,是空的。在后面可以直接def.resolve()这样调用。
这样也有一个弊端,因为执行runAsync()可以拿到def对象,而def对象上又有resolve方法,那么岂不是可以在外部就修改def的状态了?比如我把上面的代码修改如下:
现象会如何呢?并不会在2秒后输出“执行完成”,而是直接输出“在外部结束”。因为我们在异步操作执行完成之前,没等他自己resolve,就在外部给resolve了。这显然是有风险的,比如你定义的一个异步操作并指定好回调函数,有可能被别人给提前结束掉,你的回调函数也就不能执行了。
1 2 3 4 5 |
var d = runAsync(); d.then(function(data){ console.log(data) }); d.resolve('在外部结束'); |
现象会如何呢?并不会在2秒后输出“执行完成”,而是直接输出“在外部结束”。因为我们在异步操作执行完成之前,没等他自己resolve,就在外部给resolve了。这显然是有风险的,比如你定义的一个异步操作并指定好回调函数,有可能被别人给提前结束掉,你的回调函数也就不能执行了。
怎么办?jquery提供了一个promise方法,就在def对象上,他可以返回一个受限的Deferred对象,所谓受限就是没有resolve、reject等方法,无法从外部来改变他的状态,用法如下:
这样返回的对象上就没有resolve方法了,也就无法从外部改变他的状态了。这个promise名字起的有点奇葩,容易让我们搞混,其实他就是一个返回受限Deferred对象的方法,与Promise规范没有任何关系,仅仅是名字叫做promise罢了。虽然名字奇葩,但是推荐使用。
1 2 3 4 5 6 7 8 9 |
function runAsync(){ var def = $.Deferred(); //做一些异步操作 setTimeout(function(){ console.log('执行完成'); def.resolve('随便什么数据'); }, 2000); return def.promise(); //就在这里调用 } |
这样返回的对象上就没有resolve方法了,也就无法从外部改变他的状态了。这个promise名字起的有点奇葩,容易让我们搞混,其实他就是一个返回受限Deferred对象的方法,与Promise规范没有任何关系,仅仅是名字叫做promise罢了。虽然名字奇葩,但是推荐使用。
then的链式调用
既然Deferred也是Promise规范的实现者,那么其他特性也必须是支持的。链式调用的用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/div>
事实上,在此之前网上有很多文章在讲jquery Deferred对象了,但是总喜欢把ajax和Deferred混在一起讲,容易把人搞混。when、done、promise、success、error、fail、then、resolve、reject、always这么多方法不能揉在一起讲,需要把他们捋一捋,哪些是Deferred对象的方法,哪些是ajax的语法糖,我们需要心知肚明。
先讲$.Deferredjquery用$.Deferred实现了Promise规范,$.Deferred是个什么玩意呢?还是老方法,打印出来看看,先有个直观印象:
输出如下: $.Deferred()返回一个对象,我们可以称之为Deferred对象,上面挂着一些熟悉的方法如:done、fail、then等。jquery就是用这个Deferred对象来注册异步操作的回调函数,修改并传递异步操作的状态。
Deferred对象的基本用法如下,为了不与ajax混淆,我们依旧举setTimeout的例子:
在runAsync函数中,我们首先定义了一个def对象,然后进行一个延时操作,在2秒后调用def.resolve(),最后把def作为函数的返回。调用runAsync的时候将返回def对象,然后我们就可以.then来执行回调函数。 是不是感觉和ES6的Promise很像呢?我们来回忆一下第一篇中ES6的例子:
区别在何处一看便知。由于jquery的def对象本身就有resolve方法,所以我们在创建def对象的时候并未像ES6这样传入了一个函数参数,是空的。在后面可以直接def.resolve()这样调用。 这样也有一个弊端,因为执行runAsync()可以拿到def对象,而def对象上又有resolve方法,那么岂不是可以在外部就修改def的状态了?比如我把上面的代码修改如下:
现象会如何呢?并不会在2秒后输出“执行完成”,而是直接输出“在外部结束”。因为我们在异步操作执行完成之前,没等他自己resolve,就在外部给resolve了。这显然是有风险的,比如你定义的一个异步操作并指定好回调函数,有可能被别人给提前结束掉,你的回调函数也就不能执行了。 怎么办?jquery提供了一个promise方法,就在def对象上,他可以返回一个受限的Deferred对象,所谓受限就是没有resolve、reject等方法,无法从外部来改变他的状态,用法如下:
这样返回的对象上就没有resolve方法了,也就无法从外部改变他的状态了。这个promise名字起的有点奇葩,容易让我们搞混,其实他就是一个返回受限Deferred对象的方法,与Promise规范没有任何关系,仅仅是名字叫做promise罢了。虽然名字奇葩,但是推荐使用。 then的链式调用既然Deferred也是Promise规范的实现者,那么其他特性也必须是支持的。链式调用的用法如下:
|