大白话讲解Promise,搞懂jquery中的Promise

先讲$.Deferred

jquery用$.Deferred实现了Promise规范,$.Deferred是个什么玩意呢?还是老方法,打印出来看看,先有个直观印象:

JavaScript


1

2


var def = $.Deferred();

console.log(def);

输出如下:

$.Deferred()返回一个对象,我们可以称之为Deferred对象,上面挂着一些熟悉的方法如:done、fail、then等。jquery就是用这个Deferred对象来注册异步操作的回调函数,修改并传递异步操作的状态。

Deferred对象的基本用法如下,为了不与ajax混淆,我们依旧举setTimeout的例子:

JavaScript


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的例子:

JavaScript


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的状态了?比如我把上面的代码修改如下:

JavaScript


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等方法,无法从外部来改变他的状态,用法如下:

JavaScript


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规范的实现者,那么其他特性也必须是支持的。链式调用的用法如下:

JavaScript


1

2

3

4

5

6

7

8

9

10

11

12

13


var d = runAsync();

 

d.then(function(data){

    console.log(data);

    return runAsync2();

})

.then(function(data){

    console.log(data);

    return runAsync3();

})

.then(function(data){

    console.log(data);

});

与我们第一篇中的例子基本一样,可以参照。

done与fail

我们知道,Promise规范中,then方法接受两个参数,分别是执行完成和执行失败的回调,而jquery中进行了增强,还可以接受第三个参数,就是在pending状态时的回调,如下:

JavaScript

1

deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

除此之外,jquery还增加了两个语法糖方法,done和fail,分别用来指定执行完成和执行失败的回调,也就是说这段代码:

JavaScript


1

2

3

4

5


d.then(function(){

    console.log('执行完成');

}, function(){

    console.log('执行失败');

});

与这段代码是等价的:

JavaScript


1

2

3

4

5

6


d.done(function(){

    console.log('执行完成');

})

.fail(function(){

    console.log('执行失败');

});

always的用法

jquery的Deferred对象上还有一个always方法,不论执行完成还是执行失败,always都会执行,有点类似ajax中的complete。不赘述了。

$.when的用法

jquery中,还有一个$.when方法来实现Promise,与ES6中的all方法功能一样,并行执行异步操作,在所有的异步操作执行完后才执行回调函数。不过$.when并没有定义在$.Deferred中,看名字就知道,$.when,它是一个单独的方法。与ES6的all的参数稍有区别,它接受的并不是数组,而是多个Deferred对象,如下:

JavaScript


1

2

3

4

5


$.when(runAsync(), runAsync2(), runAsync3())

.then(function(data1, data2, data3){

    console.log('全部执行完成');

    console.log(data1, data2, data3);

});

jquery中没有像ES6中的race方法吗?就是以跑的快的为准的那个方法。对的,jquery中没有。

以上就是jquery中Deferred对象的常用方法了,还有一些其他的方法用的也不多,干脆就不记它了。接下来该说说ajax了。

ajax与Deferred的关系

jquery的ajax返回一个受限的Deferred对象,还记得受限的Deferred对象吧,也就是没有resolve方法和reject方法,不能从外部改变状态。想想也是,你发一个ajax请求,别人从其他地方给你取消掉了,也是受不了的。

既然是Deferred对象,那么我们上面讲到的所有特性,ajax也都是可以用的。比如链式调用,连续发送多个请求:

JavaScript


1

2

3

4

5

6

7

8

9

10

11

12

13


req1 = function(){

    return $.ajax(/*...*/);

}

req2 = function(){

    return $.ajax(/*...*/);

}

req3 = function(){

    return $.ajax(/*...*/);

}

 

req1().then(req2).then(req3).done(function(){

    console.log('请求发送完毕');

});

明白了ajax返回对象的实质,那我们用起来就得心应手了。

success、error与complete

这三个方法或许是我们用的最多的,使用起来是这样的:

JavaScript


1

2

3

4


$.ajax(/*...*/)

.success(function(){/*...*/})

.error(function(){/*...*/})

.complete(function(){/*...*/})

分别表示ajax请求成功、失败、结束的回调。这三个方法与Deferred又是什么关系呢?其实就是语法糖,success对应done,error对应fail,complete对应always,就这样,只是为了与ajax的参数名字上保持一致而已,更方便大家记忆,看一眼源码:

JavaScript


1

2

3


deferred.promise( jqXHR ).complete = completeDeferred.add;

jqXHR.success = jqXHR.done;

jqXHR.error = jqXHR.fail;

complete那一行那么写,是为了减少重复代码,其实就是把done和fail又调用一次,与always中的代码一样。deferred.promise( jqXHR )这句也能看出,ajax返回的是受限的Deferred对象。

jquery加了这么些个语法糖,虽然上手门槛更低了,但是却造成了一定程度的混淆。一些人虽然这么写了很久,却一直不知道其中的原理,在面试的时候只能答出一些皮毛,这是很不好的。这也是我写这篇文章的缘由。

jquery中Deferred对象涉及到的方法很多,本文尽量分门别类的来介绍,希望能帮大家理清思路。总结一下就是:$.Deferred实现了Promise规范,then、done、fail、always是Deferred对象的方法。$.when是一个全局的方法,用来并行运行多个异步任务,与ES6的all是一个功能。ajax返回一个Deferred对象,success、error、complete是ajax提供的语法糖,功能与Deferred对象的done、fail、always一致。就酱。

时间: 2024-10-22 15:43:24

大白话讲解Promise,搞懂jquery中的Promise的相关文章

大白话讲解Promise(一)

去年6月份, ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promise被列为正式规范.作为ES6中最重要的特性之一,我们有必要掌握并理解透彻.本文将由浅到深,讲解Promise的基本概念与使用方法.   ES6 Promise 先拉出来遛遛 复杂的概念先不讲,我们先简单粗暴地把Promise用一下,有个直观感受.那么第一个问题来了,Promise是什么玩意呢?是一个类?对象?数组?函数?   别猜了,直接打印出来看看吧,console.dir(Promise),就这么简单粗暴.

以jQuery中$.Deferred对象为例讲解promise对象是如何处理异步问题_jquery

Promises是一种令代码异步行为更加优雅的抽象,它很有可能是JavaScript的下一个编程范式,一个Promise即表示任务结果,无论该任务是否完成. 在一些现代浏览器中已经提供了原生的Promise对象,其遵循Promise/A+标准.在jQuery1.5+,提供了$.Deferred(其可以被转化为promise对象).很多知名的框架中,也提供了promise对象.promise对象在javascript中已经是一种很重要的模式,它在解决异步问题时表现出的优雅,正是javascript

jQuery中next方法用法讲解

  jQuery中next方法用法讲解         这篇文章主要介绍了jQuery中next方法用法,实例分析了jQuery中next方法的功能.定义及相关使用技巧,需要的朋友可以参考下 本文实例讲述了jQuery中next方法用法.分享给大家供大家参考.具体分析如下: 这里演示jQuery中next的用法,可取得一个包含匹配的元素集合中每一个元素紧邻的后面同辈元素的元素集合. 这个函数只返回后面那个紧邻的同辈元素,而不是后面所有的同辈元素. 可以用一个可选的表达式进行筛选 ? 1 2 3

jQuery中的Deferred和promise 的区别_jquery

Deferred和Promise之间有什么区别呢? promise 一个promise就是一个由 异步函数返回的对象 .当你想要自己编写一个这样的函数时你需要使用一个deferred. var promise = $.ajax({ url: "/myServerScript" }); promise.done(mySuccessFunction); promise.fail(myErrorFunction); var promise = $.ajax({ url: "/myS

实例讲解jquery中mouseleave和mouseout的区别_jquery

本文详细的介绍了关于jQuery中mouseleave和mouseout的区别,分享给大家供大家参考,具体内容如下 很多人在使用jQuery实现鼠标悬停效果时,一般都会用到mouseover和mouseout这对事件.而在实现过程中,可能会出现一些不理想的状况. 先看下使用mouseout的效果: <p>先看下使用mouseout的效果:</p> <div id="container" style="width: 300px;">

jQuery中$this和$(this)的区别介绍(一看就懂)_jquery

// this其实是一个Html 元素. // $this 只是个变量名,加$是为说明其是个jquery对象. // 而$(this)是个转换,将this表示的dom对象转为jquery对象,这样就可以使用jquery提供的方法操作. (function($){ $.fn.hilight = function(options){ debug(this); var defaults = { foreground: 'red', background: 'yellow' }; var opts =

js中的window.onload和jquery中的load区别的讲解

JavaScript 中的以下代码  [javascript] view plaincopyprint? Window.onload = function (){      // 编写代码 }   Window.onload = function (){ // 编写代码 }  等价于   Jquery 代码如下:  [javascript] view plaincopyprint? $(window).load(function (){        // 编写代码  });   $(windo

实例讲解Jquery中隐藏hide、显示show、切换toggle的用法_jquery

本文实例为大家分享了jquery中show().hide()和toggle()用法实例,供大家参考,具体内容如下 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>初识jQuery</title> <script src="http:/www.jb51.net/

深入解析jQuery中Deferred的deferred.promise()方法_jquery

deferred.promise() 和 .promise() 这两个API语法几乎一样,但是有着很大的差别.deferred.promise()是Deferred实例的一个方法,他返回一个Deferred.Promise实例.一个Deferred.Promise对象可以理解为是deferred对象的一个视图,它只包含deferred对象的一组方法,包括:done(),then(),fail(),isResolved(), isRejected(), always(),这些方法只能观察一个def