什么是延迟对象?

jQuery 1.5添加了“延迟对象”。 他们是什么,他们究竟做了什么?


延迟对象

从jQuery 1.5开始,Deferred对象提供了一种方法将多个回调注册到自我管理的回调队列中,根据需要调用回调队列,并转发任何同步或异步函数的成功或失败状态。

延期方法:

  • deferred.done()
  • 添加要在解析Deferred对象时调用的处理程序。
  • deferred.fail()
  • 添加要在Deferred对象被拒绝时调用的处理程序。
  • deferred.isRejected()
  • 确定一个Deferred对象是否被拒绝。
  • deferred.isResolved()
  • 确定是否已解决延迟对象。
  • deferred.reject()
  • 拒绝Deferred对象并使用给定的参数调用任何failCallback。
  • deferred.rejectWith()
  • 拒绝Deferred对象并使用给定的上下文和参数调用任何failCallbacks。
  • deferred.resolve()
  • 解析Deferred对象并使用给定的参数调用任何doneCallbacks。
  • deferred.resolveWith()
  • 解析Deferred对象并使用给定的上下文和参数调用任何doneCallbacks。
  • deferred.then()
  • 添加处理程序以在Deferred对象解析或拒绝时调用。
  • 推迟实施:

    $.get("test.php").done(
        function(){ alert("$.get succeeded"); }
    );
    
    $.get("test.php")
        .done(function(){ alert("$.get succeeded"); })
        .fail(function(){ alert("$.get failed!"); });
    

    看起来现有的ajax()方法回调可以被链接而不是在设置中声明:

    var jqxhr = $.ajax({ url: "example.php" })
        .success(function() { alert("success"); })
        .error(function() { alert("error"); })
        .complete(function() { alert("complete"); });
    

    Eric Hynds的博客文章:http://jsfiddle.net/ehynds/Mrqf8/


    jqXHR

    从jQuery 1.5开始,$ .ajax()方法返回jXHR对象,该对象是XMLHTTPRequest对象的超集。 有关更多信息,请参阅$ .ajax条目的jXHR部分


    从JQUERY 1.5发布:

    延迟对象

    随着Ajax模块的重写,引入了一项新功能,该功能也已公开发布:延迟对象。 此API允许您处理可能不会立即出现的返回值(例如来自异步Ajax请求的返回结果)。 此外,它使您能够附加多个事件处理程序(Ajax API中以前不可能的东西)。

    另外,你可以使用公开的jQuery.Deferred创建你自己的延期对象。 有关此API的更多信息可以在延迟对象文档中找到。

    Eric Hynds写了一篇关于在jQuery 1.5中使用Deferreds的优秀教程。


    而不是告诉你它做了什么,我会告诉你它做了什么并解释它。

    jQuery 1.5相关源代码的副本,注释说明它在做什么。 我认为评论大多是正确的。

    这可能是有益的

    // promiseMethods. These are the methods you get when you ask for a promise.
    // A promise is a "read-only" version
    // fullMethods = "then done fail resolve resolveWith reject rejectWith isResolve    isRejected promise cancel".split(" ")
    // As you can see it removes resolve/reject so you can't actaully trigger a
    // anything on the deferred object, only process callbacks when it "finishes".
    promiseMethods = "then done fail isResolved isRejected promise".split(" "),
    
    // Create a simple deferred (one callbacks list)
    /* Class: _Deferred.
     *  methods: done, resolve, resolveWith, isResolved
     *  internal method: cancel
     *
     *  Basically allows you to attach callbacks with the done method.
     *  Then resolve the deferred action whenever you want with an argument.
     *  All the callbacks added with done will be called with the resolved argument
     *  Any callbacks attached after resolvement will fire immediatly.
     *
     *  resolveWith allows you to set the this scope in the callbacks fired.
     *
     *  isResolved just checks whether it's resolved yet.
     *
     *  cancel blocks resolve/resolveWith from firing. the methods added throug
     *  done will never be called
     */
    _Deferred: function () {
        var // callbacks list
        callbacks = [],
            // stored [ context , args ]
            // stores the context & args that .resolve was called with
            fired,
            // to avoid firing when already doing so
            firing,
            // flag to know if the deferred has been cancelled
            // in Deferred cancel gets called after the first resolve call
            cancelled,
            // the deferred itself
            deferred = {
    
                // done( f1, f2, ...)
                done: function () {
                    if (!cancelled) {
                        var args = arguments,
                            i, length,
                            // elem in callback list
                            elem,
                            // type of elem in callback list
                            type,
                            // cached context & args for when done is called
                            // after resolve has been
                            _fired;
                        // If resolve has been called already
                        if (fired) {
                            // mark it locally
                            _fired = fired;
                            // set fired to 0. This is neccesary to handle
                            // how done deals with arrays recursively
                            // only the original .done call handles fired
                            // any that unwrap arrays and call recursively
                            // dont handle the fired.
                            fired = 0;
                        }
                        // for each function append it to the callback list
                        for (i = 0, length = args.length; i < length; i++) {
                            elem = args[i];
                            type = jQuery.type(elem);
                            // if argument is an array then call done recursively
                            // effectively unwraps the array
                            if (type === "array") {
                                // def.done([f1, f2, f3]) goes to
                                // def.done(f1, f2, f3) through the apply
                                deferred.done.apply(deferred, elem);
                            } else if (type === "function") {
                                // if its a function add it to the callbacks
                                callbacks.push(elem);
                            }
                        }
                        // if it's already been resolved then call resolveWith using
                        // the cahced context and arguments to call the callbacks
                        // immediatly
                        if (_fired) {
                            deferred.resolveWith(_fired[0], _fired[1]);
                        }
                    }
                    return this;
                },
    
                // resolve with given context and args
                resolveWith: function (context, args) {
                                    // if its been cancelled then we can't resolve
                                    // if it has fired then we can't fire again
                                    // if it's currently firing then we can't fire. This check is
                    // there because of the try finally block. It ensures we
                    // cant call resolve between the try & finally in the catch phase.
                    if (!cancelled && !fired && !firing) {
                        firing = 1;
                        // try block because your calling external callbacks
                        // made by the user which are not bugfree.
                                            // the finally block will always run no matter how bad
                                            // the internal code is.
                        try {
                            while (callbacks[0]) {
                                callbacks.shift().apply(context, args);
                            }
                                            // cache the content and arguments taht have been called
                                            // and set firing to false.
                        } finally {
                            fired = [context, args];
                            firing = 0;
                        }
                    }
                    return this;
                },
    
                // resolve with this as context and given arguments
                // just maps to resolveWith, this sets the this scope as normal
                // maps to this.promise which is the read only version of Deferred.
                resolve: function () {
                    deferred.resolveWith(jQuery.isFunction(this.promise) ? this.promise() : 
    this, arguments);
                    return this;
                },
    
                // Has this deferred been resolved?
                // checks whether it's firing or if it has fired.
                isResolved: function () {
                    return !!(firing || fired);
                },
    
                // Cancels the action. To be used internally
                cancel: function () {
                    cancelled = 1;
                    callbacks = [];
                    return this;
                }
            };
    
        return deferred;
    },
    /* Class: Deferred.
     *  methods: then, done, fail, resolve, reject, resolveWith, rejectWith, isResolved, 
    isRejected, promise
     *
     *  then is a shortcut for both assigning done & fail in one function.
     *
     *  This one has two underlying lists with different semantic meanings. You
     *  can bind to both the done callbacks and the fail callbacks then either
     *  resolve or reject your Deferred object.
     *
     *  You can check whether it has been resolved or rejected. useful to see
     *  Afterwards which one has happened.
     *
     *  Call .promise to return a new object which doesn't have the resolve/reject
     *  methods on it. This means you can only bind to it and not resolve/reject it.
     *  This is effectively read-only.
     *
     */
    // Full fledged deferred (two callbacks list)
    Deferred: function (func) {
            // the main deferred which deals with the success callbacks
        var deferred = jQuery._Deferred(),
                    // the failure deferred which deals with the rejected callbacks
            failDeferred = jQuery._Deferred(),
                    // the read only promise is cached.
            promise;
        // Add errorDeferred methods, then and promise
        jQuery.extend(deferred, {
                    // def.then([f1, f2, ...], [g1, g2, ...] is a short hand for
                    // def.done([f1, f2, ...])
            // def.fail([g1, g2, ...])
            then: function (doneCallbacks, failCallbacks) {
                            // fail exists here because this code will only run after
                            // deferred has been extended.
                deferred.done(doneCallbacks).fail(failCallbacks);
                return this;
            },
                    // map def.fail to the second underlying deferred callback list
                    // map all the other methods for rejection/failure to the underlying
                    // failDeffered object so that Deferred has two callback lists stored
                    // internally.
            fail: failDeferred.done,
            rejectWith: failDeferred.resolveWith,
            reject: failDeferred.resolve,
            isRejected: failDeferred.isResolved,
            // Get a promise for this deferred
            // If obj is provided, the promise aspect is added to the object
                    // no clue what to do with "i"
            promise: function (obj, i /* internal */ ) {
                            // if no argument is passed then just extend promise
                if (obj == null) {
                                    // if cached return the cache.
                    if (promise) {
                        return promise;
                    }
                                    // set promise & arg to be {}
                    promise = obj = {};
                }
                            // for each promiseMethods in the read only promise list
                i = promiseMethods.length;
                while (i--) {
                                    // set the deferred method on the object
                    obj[promiseMethods[i]] = deferred[promiseMethods[i]];
                }
                            // returns the "read-only" deferred without
                            // resolve, resolveWith, reject & rejectWith.
                            // So you cant "resolve" it but only add "done" functions
                return obj;
            }
        });
        // Make sure only one callback list will be used
            // if either resolve or reject is called cancel both.
            // this means that the one that has been called cant be called again
            // and the other one will never be called. So only the done or the fail
            // methods will ever be called
        deferred.then(failDeferred.cancel, deferred.cancel);
            // Don't mess with cancel!
        // Unexpose cancel
        delete deferred.cancel;
        // Call given func if any
            // function argument to be called. This was passed in. Allows you to
            // handle the deferred object after creating a new one, both as this scope
            // and as a new argument.
        if (func) {
            func.call(deferred, deferred);
        }
        return deferred;
    },
    
    /* Method: when
     * Arguments: none OR 1 of type(any & !deferred) OR n of type(deferred).
     *
     * If no arguments are passed then it gets resolved immediatly. A good way to
     * call multiple callback functions? Don't really know a good use of $.when()
     *
     * If one argument is passed and its not a deferred object then it resolves
     * immediatly and passes that argument to all the done callbacks attached.
     *
     * if n arguments are passed of type deferred object then the the done callbacks
     * will only fire if all of them succeed. If a single one fails then the
     * fail callbacks fire.
     *
     * Returns a promise read-only deferred object
     */
    // Deferred helper
    when: function (object) {
        var args = arguments,
            length = args.length,
                    // If you pass in a deferred object then set deferred to be the promise
            // if you pass in anything else then set deferred to be a new deferred
            deferred = length <= 1 && object && jQuery.isFunction(object.promise) ?
                    object :
                            jQuery.Deferred(),
            // cache the promise
            promise = deferred.promise(),
                    // store an array
            resolveArray;
    
            // if multiple objects are passed in
        if (length > 1) {
                    // create an arrey to store of values.
            resolveArray = new Array(length);
                    // for each object that we wait on
            jQuery.each(args, function (index, element) {
                            // when that object resolves then
                jQuery.when(element).then(function (value) {
                                    // store value in the array or store an array of values in it
                    resolveArray[index] = arguments.length > 1 ? slice.call(arguments, 0) : 
    value;
                                    // if length === 1 then we finished calling them all
                    if (!--length) {
                                            // resolve the deferred object with the read only promise
                                            // as context and the resolved values array as the argument
                        deferred.resolveWith(promise, resolveArray);
                    }
                            // if any fail then we reject or deferred
                }, deferred.reject);
            });
            // if deferred was newly created but there was only one argument then
        // resolve it immediatly with the argument.
        } else if (deferred !== object) {
            deferred.resolve(object);
        }
            // return the read-only deferred.
        return promise;
    },
    

    纠正我,如果我错了,但它最近点击我,它本质上是一个异步任务亚军。 承诺是一个结果合同,确保您收到...某些东西,但不保证何时能够得到它。

    链接地址: http://www.djcxy.com/p/1621.html

    上一篇: What are deferred objects?

    下一篇: Can we run multiprocessing Pool in GAE?