`
zhouyrt
  • 浏览: 1163792 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

读jQuery之二十(Deferred对象)

 
阅读更多

Deferred对象是由$.Deferred构造的,$.Deferred被实现为简单工厂模式

它用来解决JS中的异步编程,它遵循 Common Promise/A 规范。实现此规范的还有 when.js 和 dojo

 

$.Deferred作为新特性首次出现在版本1.5中,这个版本利用Deferred又完全重写了Ajax模块。

$.Deferred在jQuery代码自身四处被使用,分别是promise方法、DOM readyAjax模块、动画模块。

这里以版本1.8.3分析,由于1.7$.Callbacks从Deferred中抽离出去了,目前版本的deferred.js代码不过150行,而真正$.Deferred的实现只有100行左右。

 

$.extend标示符$上挂了两个方法,如下

jQuery.extend({
    Deferred: function( func ) {
        var tuples = [
                // action, add listener, listener list, final state
                [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
                [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
                [ "notify", "progress", jQuery.Callbacks("memory") ]
            ],
        ...

        // All done!
        return deferred;
    },

    // Deferred helper
    when: function( subordinate /* , ..., subordinateN */ ) {
        var i = 0,
            resolveValues = core_slice.call( arguments ),
            length = resolveValues.length,
            ....
 
        return deferred.promise();
    }
});

 

$.Deferred的实现

  1. 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态
  2. 创建了一个promise对象,具有state、always、then、primise方法
  3. 通过扩展primise对象生成最终的Deferred对象,返回该对象

 

$.when的实现

  1. 接受若干个对象,参数仅一个且非Deferred对象将立即执行回调函数
  2. Deferred对象和非Deferred对象混杂时,对于非Deferred对象remaining减1
  3. Deferred对象总数 = 内部构建的Deferred对象 + 所传参数中包含的Deferred对象
  4. 所传参数中所有Deferred对象每当resolve时remaining减1,直到为0时(所有都resolve)执行回调

 

这就是$.Deferred和$.when的全部了,各个方法及使用稍后介绍。

代码阅读中会发现then和when方法的实现最难理解,看多次,后感回味无穷,非常巧妙。then内部会用到不同寻常的递归,when用到了计数,每次异步成功后减一,直到为0后表示全部异步操作成功,这时才可执行回调。

 

上面提到Deferred里有3个$.Callbacks的实例,Deferred自身则围绕这三个对象进行更高层次的抽象。以下是Deferred对象的核心方法

  • done/fail/progress 是 callbacks.add,将回调函数存入
  • resolve/reject/notify 是 callbacks.fire,执行回调函数(或队列)

 

下面举一些示例看看如何使用Deferred对象。

 

一、done/resolve

function cb() {
    alert('success')
}

var deferred = $.Deferred()
deferred.done(cb)
setTimeout(function() {
    deferred.resolve()
}, 3000)

 在HTTP中表示后台返回成功状态(如200)时使用,即请求成功后可执行成功回调函数。

 

二、fail/reject

function cb() {
    alert('fail')
}

var deferred = $.Deferred()
deferred.fail(cb)
setTimeout(function() {
    deferred.reject()
}, 3000)

 在HTTP中表示后台返回非成功状态时使用,即请求失败后可执行失败回调函数。

 

三、progress/notify

function cb() {
    alert('progress')
}

var deferred = $.Deferred()
deferred.progress(cb)
setInterval(function() {
    deferred.notify()
}, 2000)

在HTTP中表示请求过程中使用,即请求过程中不断执行回调函数。这可用在文件上传时的loading百分比或进度条。

 

四、链式操作

function fn1() {
    alert('success')
}

function fn2() {
    alert('fail')
}

function fn3() {
    alert('progress')
}

var deferred = $.Deferred()
deferred.done(fn1).fail(fn2).progress(fn3) // 链式操作
setTimeout(function() {
    deferred.resolve()
    //deferred.reject()
    //deferred.notify()
}, 3000)

这样可以很方便了添加成功,失败,进度回调函数。

 

五,便利函数then,一次添加成功,失败,进度回调函数

function fn1() {
    alert('success')
}

function fn2() {
    alert('fail')
}

function fn3() {
    alert('progress')
}

var deferred = $.Deferred()
deferred.then(fn1, fn2, fn3)

调用then后还可以继续链式调用then添加多个不同回调函数,这个then也正是jQuery对 Common Promise/A 的实现。

 

六、使用always方法为成功,失败状态添加同一个回调函数

var deferred = $.Deferred()
deferred.always(function() {
    var state = deferred.state() 
    if ( state === 'resolved') {
        alert('success')
    } else if (state === 'rejected') {
        alert('fail')
    }
})

setTimeout(function() {
    deferred.resolve()
    //deferred.reject()
}, 3000)

回调函数中可以使用deferred.state方法获取异步过程中的最终状态,这里我调用的是deferred.resolve,因此最后的状态是resolved,表示成功。

 

七、when方法保证多个异步操作全部成功后才回调

function fn1() {
    alert('done1')
}

function fn2() {
    alert('done2')
}

function fn3() {
    alert('all done')
}

var deferred1 = $.Deferred()
var deferred2 = $.Deferred()

deferred1.done(fn1)
deferred2.done(fn2)

$.when(deferred1, deferred2).done(fn3)

setTimeout(function() {
    deferred1.resolve()
    deferred2.resolve()
}, 3000)

先后弹出了done1、done2、all done。 如果setTimeout中有一个reject了,fn3将不会被执行。

 

八、deferred.promise()方法返回只能添加回调的对象,这个对象与$.Deferred()返回的对象不同,只能done/fail/progress,不能resolve/reject/notify。即只能调用callbacks.add,没有callbacks.fire。它是正统Deferred对象的阉割版。

 

有了Deferred,我们使用jQuery书写ajax的风格可以这样了

$.ajax(url)
 .done(success)
 .fail(fail)

 

看似和以前比较也没什么优点,但它还可以添加多个回调

$.ajax(url)
 .done(success1)
 .done(success2)
 .fail(fail2)
 .fail(fail2)

1.5之前的则不行

 

如果多个请求完成后才算成功,1.5之前的是无法解决的,现在则可以用$.when搞定

var ajax1 = $.ajax(url1)
var ajax2 = $.ajax(url2)
$.when(ajax1, ajax2).done(success)

如果项目中有一些异步问题不妨用用Derferred。

 

相关:

http://jimliu.net/?p=64

http://www.infoq.com/cn/news/2011/09/js-promise

http://www.erichynds.com/jquery/using-deferreds-in-jquery/

http://sitr.us/2012/07/31/promise-pipelines-in-javascript.html

http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html

 

分享到:
评论

相关推荐

    谈谈jQuery之Deferred源码剖析

    jQuery的Deferred对象是jQuery在ES6的Promise概念出现之前的一种实现,它允许开发者将异步操作的结果通过链式调用的方式处理,避免了传统的层层嵌套的回调函数的写法,让代码的可读性和可维护性更高。 - **Deferred...

    2014-10-16-深入理解jQuery(4)——Deferred1

    Deferred对象是jQuery中的一种异步编程解决方案,它可以使得异步编程变得更加简洁和可读。Deferred对象的出现是为了解决异步编程中的回调函数问题,使得代码更加简洁和易于维护。 1. Deferred与Callbacks 在异步...

    jQuery的promise与deferred对象在异步回调中的作用

    总结,jQuery的Promise和Deferred对象为异步编程提供了更灵活和可读的解决方案,允许我们以更接近同步代码的方式处理异步操作。通过理解这些概念和方法,开发者可以更好地组织复杂的异步逻辑,提升代码质量。

    jQuery通过deferred对象管理ajax异步

    自jQuery 1.5版本起,引入了一种强大的异步编程模式——deferred对象。这一机制允许开发者以更为优雅和灵活的方式处理异步操作,特别是针对复杂的AJAX请求。 首先,要理解什么是异步操作。在编程中,异步操作指的是...

    详解jQuery中的deferred对象的使用(一)

    jQuery的`deferred`对象是实现异步操作的一种手段,它是对Promise/A+规范的早期实现。在jQuery 1.5及以后的版本中,`deferred`对象被引入,作为处理异步操作回调的一种更优雅的方式。 `deferred`对象的核心在于它...

    jQuery中deferred对象使用方法详解

    jQuery中的deferred对象是1.5版本之后引入的一种新的编程范式,用于处理异步操作。它提供了一种统一的接口,以更优雅的方式执行和管理异步操作。下面将详细介绍deferred对象的相关知识点,包括它的基础概念、链式回...

    Jquery高级应用Deferred对象原理及使用实例

    `jQuery` 的 `Deferred` 对象是 `Promise` 的一个强大实现,它使得异步编程更加可控和可读,减少了回调函数的嵌套,提高了代码的可维护性。在实际项目中,熟练掌握 `Deferred` 对象的使用,能够有效地提升异步操作的...

    详解JavaScript异步编程中jQuery的promise对象的作用_.docx

    jQuery 库中的 Deferred 对象是一个 Promise 对象的实现,但它没有实现对进度状态的处理。Dojo 库中的 promise 模式也提供了 Promise 对象的实现。 Promise 对象的优点 Promise 对象的优点是提供了一种简洁的方式...

    jQuery1.7压缩和未压缩版

    1. **Deferred对象和Promise接口**:1.7版本增强了对异步操作的支持,引入了Deferred对象,使得处理多个异步操作变得更加优雅。Promise接口允许开发者以链式调用的方式处理异步回调,极大地提高了代码的可读性和组织...

    jquery Deferred 快速解决异步回调的问题

    `$.Deferred()` 创建了一个Deferred对象,它可以被用于管理异步操作的状态(pending、resolved或rejected)。这个对象包含了一系列方法,允许我们监听和响应这些状态的变化。 1. **$.when()**: 这个函数用于合并多...

    jQuery中的Deferred和promise 的区别

    而Deferred对象是用来创建和控制Promise的,它允许更复杂的异步流程控制,如手动触发成功或失败,以及传递额外的信息。在实际应用中,开发者通常不需要直接使用Deferred,而是通过jQuery的API如`.ajax()`、`.get()`...

    jquery1.2.6-1.7.1测试所需

    4. **jQuery 1.5.x**:引入了 deferred 和 promise 对象,使得异步编程更加简洁和易读,这对于处理复杂的异步流程控制非常重要。同时,`.delegate()` 方法出现,它是 `.live()` 的替代品,提供了更好的性能和更多的...

    jQuery-1.7.2【包括压缩和未压缩版本】

    - **Deferred对象**:这是一个增强异步编程的功能,通过它可以更方便地处理异步操作的顺序和依赖。 - **事件委托**:改进了事件处理,支持事件委托,允许在一个父元素上绑定事件,处理其子元素的事件,提高了性能和...

    Wrox Press Professional jQuery (2012)

    使用jQuery Deferred进行高级异步编程(Advanced Asynchronous Programming with jQuery Deferred) - **Promise模式**:介绍Promise模式的基本概念及其在jQuery中的应用。 - **错误处理**:讲解如何优雅地处理异步...

    jdk1.8中文API及jQuery1.5中文API

    9. **$.Deferred()**:处理异步操作,引入Promise对象,增强了异步编程的控制和调试。 10. **$.extend()**:合并两个或更多对象的属性,常用于配置选项。 这两个API文档作为开发者的参考资料,提供了详细的函数...

    jQuery实例3可以运行

    在"jQ学习第三季"这个文件中,可能包含一系列逐步进阶的jQuery教程,覆盖了以上提到的概念和更多高级主题,如插件开发、 Deferred 对象用于异步操作的管理,以及如何与现代前端框架如React或Vue.js进行集成。...

    jqueryzepto插件把各种延迟串联起来采用管道式写法

    jQuery和Zepto提供的`$.Deferred`对象以及相关的链式操作,为我们提供了一种解决这个问题的方式。`$.Deferred`允许我们创建一个可观察的异步操作,它可以被 resolve 或 reject,并且可以通过`.then()`方法来注册回调...

    jquery_api _1.5_chm

    jQuery 1.5引入了一些重要的更新,包括对Deferred对象的支持,这使得异步操作的链式调用变得更加优雅。此外,这个版本还增强了动画性能,并修复了一些已知问题。 综上所述,jQuery API 1.5 CHM文档是开发者的宝贵...

    jquery-1.7.1(普通版、min版,1.4API中文帮助)

    - **Deferred对象(Deferred Objects)**:增强了异步编程,特别是对于AJAX和动画,提供了更灵活的控制和链式处理。 - **事件(Events)**:优化了事件处理机制,增强了事件代理和性能。 - **插件兼容性(Plugin ...

    jQuery1.5简体中文API,包好的一个帮助文档

    - **Deferred对象**:引入了Promise模式,更好地处理异步操作,使代码更加可读和可维护。 - **$.ajax的增强**:增加了全局和局部的`beforeSend`, `success`, `error`等回调,以及`dataType`选项的智能推断。 - **...

Global site tag (gtag.js) - Google Analytics