jQuery源码研究分析学习笔记-jQuery.deferred()(12)

JS是单线程语言,把每一件事情(包括GUI事件和渲染)都放在一个线程里来处理是一个很好的程序模型,因为这样就无需再考虑线程同步这些复杂问题。

但js暴露了应用开发中的一个严重问题,单线程环境看起来对用户请求响应迅速,但是当线程忙于处理其它事情时,就不能对用户的鼠标点击和键盘操作做出响应。

jQuery.deferred异步模型提供了一个抽象的非阻塞的解决方案。

jQuery.deferred()在jQ中常用的有:

  1. promise
  2. Ajax模块
  3. 动画模块
  4. DOM ready

    jQuery.Deferred(func)在jQuery.Callbacks(flags)的基础上,为回调函数增加了状态,提供了多个回调函数列表。可以通过调用方法deferred.done/fail/progress/then/always()添加成功调回调函数、失败回调函数、消息回调函数到对应的成功、失败、消息回调函数列表中,并且可通过调用方法derred.resolve/resolveWith/rejectWith/notify/notifyWith()分别触发成功、失败、消息回调函数列表。

    异步队列有三种状态:pending,resolved,rejected分别是待定、成功、失败。

    异步队列的方法列表如下:

jQuery.Deferred(func)创建异步队列步骤:

  1. 创建成功、失败、消息回调函数列表,设置初始状态为pending(待定);
  2. 创建异步队列的只读副本promise,其中包含了方法done()、fail()、progress()、state()、isResolved()、isRejected()、then()、always()、pipe()、promise()
  3. 定义异步队列deferred
  4. 如果传入函数参数func,则调用
  5. 返回异步队列deferred
jQuery.extend({

    Deferred: function( func ) {

        //成功回调函数列表,once表示回调函数列表只能被触发一次,memory表示会记录上一次触发回调函数列表时的参数,触发后添加的任何回调函数都将用记录的参数值立即调用
        var doneList = jQuery.Callbacks( "once memory" ),

            //失败回调函数列表
            failList = jQuery.Callbacks( "once memory" ),

            //消息回调函数
            progressList = jQuery.Callbacks( "memory" ),
            //初始状态,在调用方法deferred.resolve()或deferred。resolveWith()后被设置为字符串“resolved”,表示成功状态,调用方法deferred.reject()或deferred.resolveWith()后被设置为字符串“rejected”,表示失败状态
            state = "pending",

            lists = {
                resolve: doneList,
                reject: failList,
                notify: progressList
            },
            //异步队列的只读副本,前三个是引用对应的回调函数列表的方法callbacks.add()
            promise = {
                done: doneList.add,
                fail: failList.add,
                progress: progressList.add,

                //返回状态
                state: function() {
                    return state;
                },

                // Deprecated
                isResolved: doneList.fired,
                isRejected: failList.fired,

                //用户将回调函数同事添加到成功回调函数列表doneList和失败回调函数列表failList,保存两份引用,当异步队列处于成功或失败状态时被调用
                then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
                    //采用链式语法依次调用方法done(),fail(),progress()逐个添加回调函数,并返回this以绩效支持链式语法
                    deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
                    return this;
                },
                always: function() {
                    deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
                    return this;
                },

                //用来过滤当前异步队列的状态和参数,并返回一个新的异步队列的只读副本。当前异步队列被触发时,过滤函数将被调用并把返回值给只读副本
                pipe: function( fnDone, fnFail, fnProgress ) {
                    return jQuery.Deferred(function( newDefer ) {
                        jQuery.each( {
                            done: [ fnDone, "resolve" ],
                            fail: [ fnFail, "reject" ],
                            progress: [ fnProgress, "notify" ]
                        }, function( handler, data ) {
                            var fn = data[ 0 ],
                                action = data[ 1 ],
                                returned;
                            if ( jQuery.isFunction( fn ) ) {
                                deferred[ handler ](function() {
                                    returned = fn.apply( this, arguments );
                                    if ( returned && jQuery.isFunction( returned.promise ) ) {
                                        returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
                                    } else {
                                        newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
                                    }
                                });
                            } else {
                                deferred[ handler ]( newDefer[ action ] );
                            }
                        });
                    }).promise();
                },
                // Get a promise for this deferred
                // 用于返回当前异步队列的只读副本,或为一个javascript对象增加只读副本中的方法并返回。
                promise: function( obj ) {

                    //如果没有传入参数,则返回当前异步队列的只读副本promise
                    if ( obj == null ) {
                        obj = promise;
                    } else {
                    //若传入了参数obj,则把只读副本promise中的方法添加到参数obj中,从而似的参数obj具有异步队列行为,但是只包含了添加回调函数和判断状态的方法
                        for ( var key in promise ) {
                            obj[ key ] = promise[ key ];
                        }
                    }
                    return obj;
                }
            },

            //异步队列把只读副本promise中的方法添加到异步队列deferred中
            deferred = promise.promise({}),
            key;

        //为异步队列添加触发成功、失败、消息回调函数列表的方法
        for ( key in lists ) {
            deferred[ key ] = lists[ key ].fire;
            deferred[ key + "With" ] = lists[ key ].fireWith;
        }

        // 添加设置状态的回调函数
        deferred.done( function() {
            state = "resolved";
        }, failList.disable, progressList.lock ).fail( function() {
            state = "rejected";
        }, doneList.disable, progressList.lock );

        // 若传入函数参数func,则执行
        if ( func ) {
            func.call( deferred, deferred );
        }

        // 返回异步队列deferred
        return deferred;
    },
});
时间: 2024-10-05 09:15:59

jQuery源码研究分析学习笔记-jQuery.deferred()(12)的相关文章

jQuery源码研究分析学习笔记-静态方法和属性(10)

jQuery源码中定义了一些重要的静态属性和方法,它们是其他模块实现的基础,整体的源码结构如下 //把window.jQuery和winow.$备份到局部变量_jQuery和_$ _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, jQuery.extend({ //许多 JavaScript 库使用 $ 作为函数或变量名,jQuery 也一样.在 jQuery 中,$ 仅仅是 jQuery

jQuery源码研究分析学习笔记-回调函数(11)

回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用它所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应. // 工具函数,将字符串格式的标记转换为对象格式,并把转换结果缓存起来 function createFlags( flags ) { //初始化返回值object和flagsCache[flags]为空对象,同时指向了同一个空对象,当变

jQuery源码逐行分析学习01(jQuery的框架结构简化)

最近在学习jQuery源码,在此,特别做一个分享,把所涉及的内容都记录下来,其中有不妥之处还望大家指出,我会及时改正.望各位大神不吝赐教!同时,这也是我的第一篇前端技术博客,对博客编写还不是很熟悉,美化工作可能不够到位,也希望大家多多见谅! 首先这篇文章要给大家分享的是:jQuery的框架结构,把框架结构简单化处理 此处我所学习使用的jQuery版本是2.0.3版本(文件已经上传到我的文件中,大家可以去下载),一个相对比较老的版本,但是其实基本的功能都与新版本类似,该版本开发版代码共8830行.

jQuery源码逐行分析学习02(第一部分:jQuery的一些变量和函数)

第一次尝试使用Office Word,方便程度大大超过网页在线编辑,不过初次使用,一些内容不甚熟悉,望各位大神见谅~ 在上次的文章中,把整个jQuery的结构进行了梳理,得到了整个jQuery的简化结构,如下: 1 (function(){ 2 (21 , 94) 定义了一些变量和函数 jQuery = function(){}; 3 (96 , 283) 给JQ对象,添加一些方法和属性 4 (285 , 347) extend : JQ的继承方法 5 (349 , 817) jQuery.ex

jQuery源码分析系列(31) : Ajax deferred实现 - Aaron.

AJAX的底层实现都是浏览器提供的,所以任何基于api上面的框架或者库,都只是说对于功能的灵活与兼容维护性做出最优的扩展 ajax请求的流程: 1.通过 new XMLHttpRequest 或其它的形式(指IE)生成ajax的对象xhr. 2.通过xhr.open(type, url, async, username, password)的形式建立一个连接. 3.通过setRequestHeader设定xhr的请求头部(request header). 4.通过send(data)请求服务器端

二.jQuery源码解析之构建jQuery之构建函数jQuery的7种用法

一:$(selectorStr[,限制范围]),接受一个选择器(符合jQuery规范的字符串),返回一个jQuery对象;二:$(htmlStr[,文档对象]),$(html[,json对象])传入html字符串,创建一个新的dom元素 三:$(dom元素),$(dom元素集合)将dom元素转换成jQuery对象.四:$(自定义对象)封装普通对象为jQuery对象.五:$(回调函数)绑定ready事件监听函数,当Dom加载完成时执行.六:$(jQuery对象)接受一个jQuery对象,返回一个j

读jQuery源码之四(Callbacks,Deferred,when)

看了下Sizzle部分源码,核心的原理就是使用正则表达式去匹配,找到对应的原生获取元素的方法,我没有去细究了.大家有兴趣可以自己看看,分享分享! 从2850行开始,继续往下读jQuery源码(2850-3043行) 进入Callbacks(回调函数管理模块)之前,有几个扩展方法 1.dir方法 三个参数:elem——dom元素,dir——指定elem的层级名称(例如parentNode,nextSibling),until——结束判断.返回一个数组,比如获取某个元素的parentNode,如果不

javascript arguments对象研究--针对jquery源码研究再研究

外部插件: $.fn.tinytip = function(text, customOptions) { debugger; if (text && typeof text === 'object'){ customOptions = text; text = customOptions.tooltip; } var options = $.extend({}, tooltip_options, customOptions); options.tooltip = text; if (typ

jQuery 源码解析一:jQuery 类库整体架构设计解析

如果是做 web 的话,相信都非要对 Dom 进行增删查改,那这相信大家都或多或少接触到过 jQuery 类库,其最大特色就是强大的选择器,让开发者脱离原生 JS 一大堆 getElementById.getElementsByName...官方提供超长方法 api . jQuery 整体源码,本人也还在阅读中,暂时记录一下.(为什么要看源码,原因很简单---- 一 好好了解一下 jQuery 原理  二 为了装逼显摆).   一  使用 jQuery 时候,首先需引入 jQuery 文件,而之