Depth study Deferred object and holdReady jquery source of ()

Depth study Deferred object and holdReady jquery source of ()

jQuery's Deferred objects have resolve, reject, then the method, as well as done, fail, always ...... method. jQuery Deferred object is to use the asynchronous operation to the callback function is registered, modified and transferred asynchronous operation state.

<script>
    var defer = $.Deferred();
    console.log(defer);
</script>

I have been using the jquery ajax

          $.ajax({
                  url: 'abc.com',
                  type: 'post',
                  data: { abc:1 },
                  success: function (data) {
                      if (!data.success) {
                          alert(data.message);
                      } else {
  
                     }
                 }
             });

All methods fail will reject the callback method Deferred object, resolve method calls back all done

   $.ajax({
       url: 'abc.com/index',
       type: 'post',
       data: { abc:1 },
  }).done(function(data) {
      if (!data.success) {
           alert(data.message);    
       } else {
       }
  }).fail(function() {
      alert('请稍后重试');
  });
  function test(txt) {
      var dtd = $.Deferred();
      if (!txt.trim()) {
          dtd.reject({ msg: '不能为空' });
      } else if (!reg.test(txt)) {
          dtd.reject({ msg: '含有非法字符' });
      } else if (this.tags.indexOf(txt)>=0) {
          dtd.reject({ msg: '已重复' });
      }
   dtd.resolve();
     return dtd.promise();
 }
 
 调用:
     test('xxx')
     .done(function(data){  
      //xxxxxx
     })
     .fail(function(data){ 
       //xxxx
     })

Examples defer Deferred method to resolve the object by the parameter "asynchronous request returned after a successful data" then back to the reception ,, printing process.

    function runAsync(){
        var defer = $.Deferred();
        //做一些异步操作
        setTimeout(function(){
            console.log('执行完成');
            defer.resolve('异步请求成功之后返回的数据');
        }, 1000);
        return defer;
    }
    runAsync().then(function(data){
        console.log(data)
    });

And Promise of difference ES6

    function runAsync(){
        var p = new Promise(function(resolve, reject){
           
            setTimeout(function(){
                console.log('执行完成');
                resolve('异步请求成功之后返回的数据');
            }, 1000);
        });
        return p;            
    }

    runAsync().then(function(data){
        console.log(data);
    });

1. Deferred object is created when there is no mass participation; and create a Promise object when passed parameters (pass an anonymous function, the function has two parameters: resolve, reject);

2, Deferred object directly resolve the method call; Promise and resolve the object method is invoked internally;

Description: Deferred resolve itself the object method, the object is achieved by performing the Promise resolve method, constructor, assigned to the state of the object Promise execution result.

So there is a downside: Because Deferred object method comes with resolve, then get the Deferred object, you can call at any time to resolve the method, its status can be manually intervened

Direct Deferred provided directly to the external state, print "outside end", after the print 1s "execution is complete," do not print "data returned after an asynchronous request success" a.

Obviously, this is not good. I send asynchronous requests have not received data on the people on the outside to give me over. . . . . . .

    function runAsync(){
        var defer = $.Deferred();
        //做一些异步操作
        setTimeout(function(){
            console.log('执行完成');
            defer.resolve('异步请求成功之后返回的数据');
        }, 1000);
        return defer;
    }
   var der = runAsync();
   der.then(function(data){
        console.log(data)
   });
   der.resolve('在外部结束'); 

Methods promise a Deferred object, Deferred object is a limited

The so-called limited Deferred object, the object is no resolve and Deferred reject the method. This will not change the state of the Deferred object outside.

    function runAsync(){
        var def = $.Deferred();
        //做一些异步操作
        setTimeout(function(){
            console.log('执行完成');
            def.resolve('请求成功之后返回的数据');
        }, 2000);
        return def.promise(); //就在这里调用
    }

then the method and done Deferred object, fail syntactic sugar

We know that the Promise ES6 specification, then the method takes two parameters, namely the implementation of the completion and implementation of the callback failed, but in jquery been enhanced to also accept a third argument, the pullback in the pending state, as follows:

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

The method then also Deferred object can be chained operations.

    function runAsync(){
        var def = $.Deferred();
        //做一些异步操作
        setTimeout(function(){
              var num = Math.ceil(Math.random()*10); //生成1-10的随机数
               if(num<=5){
                   def.resolve(num);
               }
               else{
                   def.reject('数字太大了');
               }
        }, 2000);
        return def.promise(); //就在这里调用
    }

    runAsync().then(function(d){
        console.log("resolve");
        console.log(d);
    },function(d){
        console.log("reject");
        console.log(d);
    })

done, fail syntactic sugar , and are used to specify the failed execution completion callback, and this code is equivalent to:

    function runAsync(){
        var def = $.Deferred();
        //做一些异步操作
        setTimeout(function(){
              var num = Math.ceil(Math.random()*10); //生成1-10的随机数
               if(num<=5){
                   def.resolve(num);
               }
               else{
                   def.reject('数字太大了');
               }
        }, 2000);
        return def.promise(); //就在这里调用
    }

    runAsync().done(function(d){
        console.log("resolve");
        console.log(d);
    }).fail(function(d){
        console.log("reject");
        console.log(d);
    })

always usage

Deferred object on jquery always there is a method, whether complete or fails to perform, always will be executed, somewhat similar to the ajax complete.

$ .When usage

jquery, there is a $ .when way to implement Promise, as with all methods ES6 function in parallel to perform asynchronous operations, before the implementation of the callback function at all after the implementation of asynchronous operations. But $ .when not defined in the $ .Deferred in to see the name to know, $. When, it is a separate method. And all of the parameters for ES6 slightly different, it is not acceptable to the array, but a plurality Deferred object, as follows:

 function runAsync(){
        var def = $.Deferred();
        //做一些异步操作
        setTimeout(function(){
              var num = Math.ceil(Math.random()*10); //生成1-10的随机数
              def.resolve(num);   
        }, 2000);
        return def.promise(); //就在这里调用
    }
    $.when(runAsync(), runAsync(), runAsync()) .then(function(data1, data2, data3){
     console.log('全部执行完成');
     console.log(data1, data2, data3);
  });

Timers are used to replace the disposable asynchronous request for data processing. Why is it useless ajax, not because of trouble in here to say what ajax and Deferred contact:

jquery ajax return of a limited Deferred object , a method that is no resolve and reject methods, can not change the state from the outside, since it is a Deferred object, then all the features we mentioned above, ajax are also can be used. For example call chain, continuously transmitting a plurality of requests:

req1 = function(){
    return $.ajax(/* **** */);
}
req2 = function(){
    return $.ajax(/* **** */);
}
req3 = function(){ 
  return $.ajax(/* **** */);
}
req1().then(req2).then(req3).done(function(){ console.log('请求发送完毕'); });

success、error与complete

These three methods we used ajax syntax sugar.

$.ajax(/*...*/)
.success(function(){/*...*/})
.error(function(){/*...*/})
.complete(function(){/*...*/})

Sometimes I prefer to be treated as property internally.

Ajax request indicate success, failure, end callbacks. These three methods and Deferred then what does it matter? In fact, syntactic sugar, success corresponds done, error corresponding to fail, complete correspondence always, so, just to be consistent with the parameters ajax name only.

to sum up:

$ .Deferred achieved Promise norm, then, done, fail, always is a method Deferred object. $ .When a global method for a plurality of asynchronous tasks running in parallel, and is a function of all ES6. ajax returns a Deferred object limited, success, error, complete syntactic sugar ajax provided, done function Deferred object, fail, always consistent.

 

jquery source

    // The deferred used on DOM ready
    var readyList;

    jQuery.fn.ready = function (fn) {
        // Add the callback
        jQuery.ready.promise().done(fn);

        return this;
    };

    jQuery.extend({
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,

        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,

        // Hold (or release) the ready event
        holdReady: function (hold) {
            if (hold) {
                jQuery.readyWait++;
            } else {
                jQuery.ready(true);
            }
        },

        // Handle when the DOM is ready
        ready: function (wait) {

            // Abort if there are pending holds or we're already ready
            if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
                return;
            }

            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if (!document.body) {
                return setTimeout(jQuery.ready);
            }

            // Remember that the DOM is ready
            jQuery.isReady = true;

            // If a normal DOM Ready event fired, decrement, and wait if need be
            if (wait !== true && --jQuery.readyWait > 0) {
                return;
            }

            // If there are functions bound, to execute
            readyList.resolveWith(document, [jQuery]);

            // Trigger any bound ready events
            if (jQuery.fn.triggerHandler) {
                jQuery(document).triggerHandler("ready");
                jQuery(document).off("ready");
            }
        }
    });

    /**
     * Clean-up method for dom ready events
     */
    function detach() {
        if (document.addEventListener) {
            document.removeEventListener("DOMContentLoaded", completed, false);
            window.removeEventListener("load", completed, false);

        } else {
            document.detachEvent("onreadystatechange", completed);
            window.detachEvent("onload", completed);
        }
    }

    /**
     * The ready event handler and self cleanup method
     */
    function completed() {
        // readyState === "complete" is good enough for us to call the dom ready in oldIE
        if (document.addEventListener || event.type === "load" || document.readyState === "complete") {
            detach();
            jQuery.ready();
        }
    }

    jQuery.ready.promise = function (obj) {
        if (!readyList) {

            readyList = jQuery.Deferred();

            // Catch cases where $(document).ready() is called after the browser event has already occurred.
            // we once tried to use readyState "interactive" here, but it caused issues like the one
            // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
            if (document.readyState === "complete") {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                setTimeout(jQuery.ready);

                // Standards-based browsers support DOMContentLoaded
            } else if (document.addEventListener) {
                // Use the handy event callback
                document.addEventListener("DOMContentLoaded", completed, false);

                // A fallback to window.onload, that will always work
                window.addEventListener("load", completed, false);

                // If IE event model is used
            } else {
                // Ensure firing before onload, maybe late but safe also for iframes
                document.attachEvent("onreadystatechange", completed);

                // A fallback to window.onload, that will always work
                window.attachEvent("onload", completed);

                // If IE and not a frame
                // continually check to see if the document is ready
                var top = false;

                try {
                    top = window.frameElement == null && document.documentElement;
                } catch (e) { }

                if (top && top.doScroll) {
                    (function doScrollCheck() {
                        if (!jQuery.isReady) {

                            try {
                                // Use the trick by Diego Perini
                                // http://javascript.nwbox.com/IEContentLoaded/
                                top.doScroll("left");
                            } catch (e) {
                                return setTimeout(doScrollCheck, 50);
                            }

                            // detach all dom ready events
                            detach();

                            // and execute any waiting functions
                            jQuery.ready();
                        }
                    })();
                }
            }
        }
        return readyList.promise(obj);
    };
	

	    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")]
                ],
                state = "pending",
                promise = {
                    state: function () {
                        return state;
                    },
                    always: function () {
                        deferred.done(arguments).fail(arguments);
                        return this;
                    },
                    then: function ( /* fnDone, fnFail, fnProgress */) {
                        var fns = arguments;
                        return jQuery.Deferred(function (newDefer) {
                            jQuery.each(tuples, function (i, tuple) {
                                var fn = jQuery.isFunction(fns[i]) && fns[i];
                                // deferred[ done | fail | progress ] for forwarding actions to newDefer
                                deferred[tuple[1]](function () {
                                    var returned = fn && fn.apply(this, arguments);
                                    if (returned && jQuery.isFunction(returned.promise)) {
                                        returned.promise()
                                            .done(newDefer.resolve)
                                            .fail(newDefer.reject)
                                            .progress(newDefer.notify);
                                    } else {
                                        newDefer[tuple[0] + "With"](this === promise ? newDefer.promise() : this, fn ? [returned] : arguments);
                                    }
                                });
                            });
                            fns = null;
                        }).promise();
                    },
                    // Get a promise for this deferred
                    // If obj is provided, the promise aspect is added to the object
                    promise: function (obj) {
                        return obj != null ? jQuery.extend(obj, promise) : promise;
                    }
                },
                deferred = {};

            // Keep pipe for back-compat
            promise.pipe = promise.then;

            // Add list-specific methods
            jQuery.each(tuples, function (i, tuple) {
                var list = tuple[2],
                    stateString = tuple[3];

                // promise[ done | fail | progress ] = list.add
                promise[tuple[1]] = list.add;

                // Handle state
                if (stateString) {
                    list.add(function () {
                        // state = [ resolved | rejected ]
                        state = stateString;

                        // [ reject_list | resolve_list ].disable; progress_list.lock
                    }, tuples[i ^ 1][2].disable, tuples[2][2].lock);
                }

                // deferred[ resolve | reject | notify ]
                deferred[tuple[0]] = function () {
                    deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments);
                    return this;
                };
                deferred[tuple[0] + "With"] = list.fireWith;
            });

            // Make the deferred a promise
            promise.promise(deferred);

            // Call given func if any
            if (func) {
                func.call(deferred, deferred);
            }

            // All done!
            return deferred;
        },

        // Deferred helper
        when: function (subordinate /* , ..., subordinateN */) {
            var i = 0,
                resolveValues = slice.call(arguments),
                length = resolveValues.length,

                // the count of uncompleted subordinates
                remaining = length !== 1 || (subordinate && jQuery.isFunction(subordinate.promise)) ? length : 0,

                // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
                deferred = remaining === 1 ? subordinate : jQuery.Deferred(),

                // Update function for both resolve and progress values
                updateFunc = function (i, contexts, values) {
                    return function (value) {
                        contexts[i] = this;
                        values[i] = arguments.length > 1 ? slice.call(arguments) : value;
                        if (values === progressValues) {
                            deferred.notifyWith(contexts, values);

                        } else if (!(--remaining)) {
                            deferred.resolveWith(contexts, values);
                        }
                    };
                },

                progressValues, progressContexts, resolveContexts;

            // add listeners to Deferred subordinates; treat others as resolved
            if (length > 1) {
                progressValues = new Array(length);
                progressContexts = new Array(length);
                resolveContexts = new Array(length);
                for (; i < length; i++) {
                    if (resolveValues[i] && jQuery.isFunction(resolveValues[i].promise)) {
                        resolveValues[i].promise()
                            .done(updateFunc(i, resolveContexts, resolveValues))
                            .fail(deferred.reject)
                            .progress(updateFunc(i, progressContexts, progressValues));
                    } else {
                        --remaining;
                    }
                }
            }

            // if we're not waiting on anything, resolve the master
            if (!remaining) {
                deferred.resolveWith(resolveContexts, resolveValues);
            }

            return deferred.promise();
        }
    });

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Published 370 original articles · won praise 88 · views 290 000 +

Guess you like

Origin blog.csdn.net/qq_35029061/article/details/85278027