jQuery 1.5 adds "Deferred Objects". What are they, and what exactly do they do?
问题:
回答1:
Deferred Object
As of jQuery 1.5, the Deferred object provides a way to register multiple callbacks into self-managed callback queues, invoke callback queues as appropriate, and relay the success or failure state of any synchronous or asynchronous function.
Deferred Methods:
- deferred.done()
- Add handlers to be called when the Deferred object is resolved.
- deferred.fail()
- Add handlers to be called when the Deferred object is rejected.
- deferred.isRejected()
- Determine whether a Deferred object has been rejected.
- deferred.isResolved()
- Determine whether a Deferred object has been resolved.
- deferred.reject()
- Reject a Deferred object and call any failCallbacks with the given args.
- deferred.rejectWith()
- Reject a Deferred object and call any failCallbacks with the given context and args.
- deferred.resolve()
- Resolve a Deferred object and call any doneCallbacks with the given args.
- deferred.resolveWith()
- Resolve a Deferred object and call any doneCallbacks with the given context and args.
- deferred.then()
- Add handlers to be called when the Deferred object is resolved or rejected.
Deferred In Action:
$.get("test.php").done( function(){ alert("$.get succeeded"); } ); $.get("test.php") .done(function(){ alert("$.get succeeded"); }) .fail(function(){ alert("$.get failed!"); });
And it seems that the existing ajax() method callbacks can be chained rather than declared in the settings:
var jqxhr = $.ajax({ url: "example.php" }) .success(function() { alert("success"); }) .error(function() { alert("error"); }) .complete(function() { alert("complete"); });
Working Example From Eric Hynds blog post: http://jsfiddle.net/ehynds/Mrqf8/
jqXHR
As of jQuery 1.5, the $.ajax() method returns the jXHR object, which is a superset of the XMLHTTPRequest object. For more information, see thejXHR section of the $.ajax entry
From JQUERY 1.5 RELEASED:
DEFERRED OBJECTS
Along with the rewrite of the Ajax module a new feature was introduced which was also made publicly available: Deferred Objects. This API allows you to work with return values that may not be immediately present (such as the return result from an asynchronous Ajax request). Additionally it gives you the ability to attach multiple event handlers (something that wasn’t previously possible in the Ajax API).
Additionally you can make your own deferred objects using the exposed jQuery.Deferred. More information about this API can be found in the Deferred Object documentation.
Eric Hynds has written up a good tutorial on Using Deferreds in jQuery 1.5.
回答2:
Rather then telling you what it does, I'll show you what it does and explain it.
A copy of the related source of jQuery 1.5 with annotating explaining what it's doing. I think the comments are mostly correct.
This may be of benefit
// 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 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; },
回答3:
Correct me if i'm wrong, but it recently clicked for me that it's essentially an Asynchronous Task Runner. The promise is a result contract, ensuring you receive ...something, but without guarantee of when you'll get it.
回答4:
While working in Javascript, we encounter situation where function calls are asynchronous. That is the calee function's (let say X) flow does not wait for the called asynchronous function (Let say Y). Typical example is when we make calls to a server to fetch some data from a database or an HTML page. If those calls were not asynchronous, the user interface will be stuck waiting for the server to respond. This asynchronous nature leads to a problem when you want to execute things in an order, for example, you want to print something after Y (asynch) is done executing or done fetching data. Here jQuery provide us with Deffered Object. Basically, jQuery has taken care of all boilerplate code that usually we write to resolve this situation. Here is a simple example:
$.ajax({ ... }).done(function(){ //write here what you wish to do when this ajax call is success }).fail(function(){ //write here what you wish to do on failure of this ajax call }); //see more on jQuery Deferred page
You can write your own deferred (asynch) function
function DoSomethingTimeConsumingAsynch(){ var deferred = $.Deferred(); _.defer(function(){ //I am using underscore, you can also use setTimeout ... deferred.resolve();//When the process is done successfully ... deferred.reject(); //When the process has failed }); return deferred; } //HEre how to use your own asynch function DoSomethingTimeConsumingAsynch() .done(function(){ //this will be invoked on success }) .fail(function(){ //this will be invoked on failure })
I hope this helped.