jQuery之Deferred解读

本文深入解析了jQuery中的Deferred对象实现原理及用法,包括其内部结构、状态管理、回调队列等核心概念,并提供了多个示例代码来展示如何使用Deferred进行异步任务的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

针对用的比较多的Deferred进行解读,所有注解都在代码行中



(function (jQuery) {
    var sliceDeferred = [].slice;
    jQuery.extend({
        Deferred: function (func) {
            var doneList = jQuery.Callbacks("once memory"),//成功回调函数列表
                failList = jQuery.Callbacks("once memory"),//失败回调函数列表
                progressList = jQuery.Callbacks("memory"),//消息过程回调函数列表
                state = "pending",//初始状态 还有 resolved、rejected
                lists = {
                    resolve: doneList,
                    reject: failList,
                    notify: progressList
                },
                //异步队列的只读副本
                promise = {
                    done: doneList.add, //添加到成功回调函数列表的方法
                    fail: failList.add, //添加到失败回调函数列表的方法
                    progress: progressList.add,//添加到消息过程回调函数的列表方法

                    state: function () {
                        return state;
                    },
                    isResolved:doneList.fired,//成功回调函数列表是否被执行
                    isRejected: failList.fired,//失败回调函数列表是否被执行
                    then: function (doneCallbacks, failCallbacks, progressCallbacks) {//快速添加到成功、失败、消息回调函数列表方法
                        deferred.done(doneCallbacks).fail(failCallbacks).progress(progressCallbacks);
                        return this;
                    },
                    always: function () { 
                        deferred.done.apply(deferred, arguments).fail.apply(deferred, arguments);
                        return this;
                    },
                    //工具方法,过滤当前异步队列的状态和参数,并且返回一个新的异步队列副本
                    //处理ajax中嵌套ajax ,这个简称过滤器
                    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();
                    },
                    promise: function (obj) {
                        if (obj == null) {
                            obj = promise;
                        } else {
                            for (var key in promise) {
                                obj[key] = promise[key];
                            }
                        }
                        return obj;
                    }
                },
                //把只读副本promise中的方法添加到异步队列deferred中
                deferred = promise.promise({}),//异步队列
                key;
            //添加触发成功、失败、消息过程回调函数列表的方法
            for (key in lists) {
                //deferred.resolve=doneList.fire
                //deferred.reject=failList.fire
                //deferred.notify=progressList.fire
                deferred[key] = lists[key].fire;
                //deferred.resolveWith=doneList.fireWith
                //deferred.rejectWith=failList.fireWith
                //deferred.notifyWith=progressList.fireWith
                deferred[key + "With"] = lists[key].fireWith;
            }

            //分别在deferred中追加三个成功回调函数、三个失败函数
            deferred.done(function () {
                state = "resolved";
            }, failList.disable, progressList.lock).fail(function () {
                state = "rejected";
            }, doneList.disable, progressList.lock);

            //如果传递了函数类型的参数,就执行
            if (func) {
                //如果传入的参数为function,调用参数函数时,指定上下文对象为deferred,参数为deferred
                //这样传入的函数可以调用deferred的方法
                func.call(deferred, deferred);
            }

            //全部处理完成
            return deferred;
        },
        //Deferred帮助类 jQuery.when(deferreds)
        when: function (firstParam) {
            //arguments 其实是一个对象,有点类似数组,这里通过[].slice.call(arguments,0)转换为数组
            //但是如果是真实的object={name:'',age:30}这种,[].slice.call(object,0)是行不通的
            var args = sliceDeferred.call(arguments, 0), 
                i = 0,
                length = args.length,
                pValues = new Array(length),
                count = length,
                pCount = length,
                deferred = length <= 1 && firstParam && jQuery.isFunction(firstParam.promise) ? firstParam : jQuery.Deferred(),
                promise = deferred.promise();

            function resolveFunc(i){
                return function (value) {
                    args[i] = arguments.length > 1 ? sliceDeferred.call(arguments, 0) : value;
                    if (!(--count)) {
                        deferred.resolveWith(deferred, args);
                    }
                };
            }
            function progressFunc(i) {
                return function (value) {
                    pValues[i] = arguments.length > 1 ? sliceDeferred.call(arguments, 0) : value;
                    deferred.notifyWith(promise, pValues);
                };
            }

            if (length > 1) {
                for (; i < length; i++) {
                    if (args[i] && args[i].promise && jQuery.isFunction(args[i].promise)) {
                        args[i].promise().then(resolveFunc(i), deferred.reject, progressFunc(i));
                    } else {
                        --count;
                    }
                }
                if (!count) {
                    deferred.resolveWith(deferred, args);
                }
            } else if (deferred !== firstParam) {
                deferred.resolveWith(deferred, length ? [firstParam] : []);
            }
            return promise;
        }
    });
})(jQuery)

//对Pipe使用的讲解
//Demo--01
var defer = $.Deferred(),
    filtered = defer.pipe(function (value) {
        return value * 2;
    });

defer.resolve(5);
filtered.done(function (value) {
    alert("Value is ( 2*5 = ) 10: " + value);
});

//Demo--02
var defer = $.Deferred(),
    filtered = defer.pipe(null, function (value) {
        return value * 3;
    });

defer.reject(6);
filtered.fail(function (value) {
    alert("Value is ( 3*6 = ) 18: " + value);
});

//Demo--03
var request = $.ajax(url, { dataType: "json" }),
    chained = request.pipe(function (data) {
        return $.ajax(url2, { data: { user: data.userId } });
    });

chained.done(function (data) {
    //url2返回后的数据
});


//对When的使用方法
//Demo--01
var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();

$.when(d1, d2, d3).done(function (v1, v2, v3) {
    console.log(v1); // v1 is undefined
    console.log(v2); // v2 is "abc"
    console.log(v3); // v3 is an array [ 1, 2, 3, 4, 5 ]
});

//Demo--02
$.when($.ajax("/page1"), $.ajax("/page2")).done(function (a1, a2) {
    /* a1 and a2 are arguments resolved for the
        page1 and page2 ajax requests, respectively */
    var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
    if (/Whip It/.test(jqXHR.responseText)) {
        console.log("第一个页面的数据");
    }
});

//Demo--03 then为快捷的done、fail、progress
$.when($.ajax("test.aspx")).then(function (data, textStatus, jqXHR) {
    alert(jqXHR.status); 
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值