Home  >  Article  >  Web Front-end  >  Code for using deferred objects in jQuery 1.5 (translation)_jquery

Code for using deferred objects in jQuery 1.5 (translation)_jquery

WBOY
WBOYOriginal
2016-05-16 18:09:371128browse

Translator's Note:
1. Deferred is a new feature of jQuery1.5. Many people translate it as "Asynchronous queue", I think is more reliable, after all, it has nothing to do with "delay", but I still use the word deferred in this article.

2. This article is mentioned in the jQuery1.5 release blog, and it is also the most classic and in-depth article introducing deferred. In view of the fact that there are currently relatively few Chinese materials, they are specially translated for everyone’s study and reference.

3. The whole article adopts free translation. If there is any inappropriateness, please feel free to point it out.

The Deferreds object newly added in jQuery1.5 can decouple the processing method of task completion from the task itself. This is nothing new in the JavaScript community, as the two JS frameworks Mochikit and Dojo have implemented this feature for a long time. But with Julian Aubourg rewriting the AJAX module in jQuery 1.5, deferreds have naturally become the internal implementation logic. Using deferreds objects, multiple callback functions can be bound to be executed when the task is completed, or even after the task is completed. These tasks can be asynchronous or synchronous.

More importantly, deferreds have been implemented as an internal implementation of $.ajax(), so you can automatically get the traversal brought by deferreds when calling AJAX. For example, we can bind the callback function like this:

Copy the code The code is as follows:

// $ .get, asynchronous AJAX request
var req = $.get('foo.htm').success(function (response) {
// AJAX processing function after success
}).error( function () {
// AJAX failure post-processing function
});
// This function may call
doSomethingAwesome() before AJAX ends;
// Add another AJAX Callback function, AJAX may have ended at this time, or it may not have ended yet
// Since $.ajax has built-in deferred support, we can write like this
req.success(function (response) {
/ / This function will be called after AJAX has finished, or immediately if AJAX has finished
});

We are no longer limited to only one success, failure or completion callback function . Instead, callback functions that are added at any time are placed in a first-in, first-out queue.
As can be seen from the above example, the callback function can be attached to the AJAX request (any observable task), even after the AJAX request has ended. The organization of the code is very good, we no longer need to write long callback functions. It's like $.queue() meets pub/sub (publish-subscribe mechanism, generally used in event-based models).
Going deeper, imagine a scenario like this, after some concurrent AJAX requests have all ended Execute a callback function. I can easily accomplish this through jQuery’s function $.when():
Copy code The code is as follows:

function doAjax() {
return $.get('foo.htm');
}

function doMoreAjax() {
return $.get('bar. htm');
}

$.when(doAjax(), doMoreAjax()).then(function () {
console.log('I fire once BOTH ajax requests have completed! ');
}).fail(function () {
console.log('I fire if one or more requests failed.');
});

Open the example in jsFiddle

The above example works properly thanks to the fact that the return value of each jQuery AJAX method contains a promise function to track asynchronous requests. The return value of the Promise function is a read-only view of the deferred object. (The promise is a read-only view into the result of the task.) Deferreds determine whether the current object is observable by detecting whether the promise() function exists in the object. $.when() will wait for all AJAX requests to end, and then call the callback functions registered through .then(), .fail() (the specific callback functions called depend on the end status of the task). These callback functions will be executed in the order in which they were registered.

Even better, $.when() accepts a function or an array of functions as parameters (Translator’s Note: This is not quite right, $.when accepts one or more deferred objects, or native JS Object. Note that function arrays cannot be used as parameters), so you can combine these asynchronous tasks at will.

$.ajax() returns an object, which is associated with some deferred functions, such as promise(), then(), success(), error() . However, you cannot operate the original deferred object, only the promise() function (Translator's Note: Remember the promise just mentioned is a read-only view), and the isRejected() and isResolved() functions that can detect the deferred status.

But why not return a deferred object? If a complete deferred object is returned, then we have more control and may be able to trigger the deferred object at will (Translator's Note: I translated resolve as trigger, which is to trigger all callback functions registered on the deferred object) deferred object, thus Causes all callback functions to be executed before the AJAX request ends. Therefore, to avoid potentially breaking the whole paradigm, only return the dfd.promise(). promise().) (Translator’s Note: If you are confused about the exact meaning of the above paragraphs, it doesn’t matter. I will write an article later to analyze the reasons in depthRegistering callback function (Registering Callbacks) In the above example, we use then(), success(), fail() methods to register callback functions. In fact, there are more methods that can be used, especially when processing AJAX requests. The method depends on your concern about the result status.
Functions available for all deferred objects (AJAX, $.when or manually created deferred objects):


.then( doneCallbacks, failedCallbacks )
.done( doneCallbacks )
.fail( failCallbacks )


The AJAX object contains 3 additional methods, two of which will be mapped to the methods mentioned above. These methods are mainly for compatibility with previous code:


// "success" and "error" will be mapped to the "done" and "fail" methods respectively
. success( doneCallbacks )
.error( failCallbacks )


You can also register a complete callback function, which will be called after the request is completed, regardless of whether the request is successful or failed. The success or error function, and the complete function are actually the done function alias of a separate deferred object. This deferred object created inside $.ajax() will trigger the callback function (resolve) after AJAX ends.


Copy code
The code is as follows: .complete( completeCallbacks )
Therefore, the following The three examples are equivalent (in the context of AJAX, success seems more comfortable than the done function, right? ) (Translator’s note: Actually it’s because we are familiar with the previous AJAX calling methods and have preconceived ideas, or mindset):



Copy code
The code is as follows: $.get("/foo/").done( fn ); // Equivalent to:
$.get("/foo /").success( fn );
// Equivalent to:
$.get("/foo/", fn );


Creating your own Deferred
We know that $.ajax and $.when implement the deferred interface internally, but we can also create deferred objects manually:
Copy code The code is as follows:

function getData() {
return $.get('/foo/');
}
function showDiv() {
var dfd = $.Deferred();
$('#foo').fadeIn(1000, dfd.resolve);
return dfd. promise();
}
$.when(getData(), showDiv()).then(function (ajaxResult) {
console.log('The animation AND the AJAX request are both done!' ; >Open the example in jsFiddle



In showDiv(), we create a deferred object, perform an animation, and then return a promise. This deferred object will be triggered (resolved) after fadeIn() ends. Between the return of this promise and the triggering of the deferred object (note: the deferred here refers to the object created by $.when, not the object returned by showDiv()), a then() callback function will be registered. This callback function will be executed after both asynchronous tasks have completed. getData() returns an object (Translator's Note: It is actually an XMLHttpRequest object encapsulated by jQuery) with a promise method, which allows $.when() to monitor the end of this AJAX request. The manual steps we took to return a promise in showDiv() is handled for us internally by $.ajax() and $.when(). 1/15/2011: Julian pointed out in the comments that the above syntax works Reduced to $.Deferred(fn).promise(). Therefore, the following codes at both ends are equivalent: Copy the code


The code is as follows:
function showDiv() {
return $.Deferred(function (dfd) {
$('#foo').fadeIn(1000, dfd.resolve);
}).promise();
}


Add callback functions for custom deferred objects (Defer your Deferreds)
We can go one step further and provide getData() and showDiv() registers callback functions separately, just like we register callback functions in $.then(). (Translator’s note: The following paragraphs are repetitive and have the same meaning, so I won’t translate them. Let’s look at the code)




Copy code


The code is as follows:
return $.Deferred(function (dfd) {
// Translator's Note: This paragraph The code is not in the original text, but it appears in jsFiddle.
// I think this is the author’s original intention, to register a callback function for the custom deferred function
dfd.done(function () {
console. log('Fires after the animation succeeds');
});
$('#foo').fadeIn(1000, dfd.resolve);
}).promise();
}
$.when(getData(), showDiv()).then(function (ajaxResult) {
console.log('Fires after BOTH showDiv() AND the AJAX request succeed!');
// 'ajaxResult' is the result returned by the server
});





Open the example in jsFiddle



Chaining Hotness Deferred's callback function can be called in a chain, as long as the function returns a deferred object (Translator's Note: dfd.promise() returns a read-only deferred object ). This is an actual code (via @ajpiano!) Copy the code

The code is as follows:

function saveContact(row) {
var form = $.tmpl(templates["contact-form"]),
valid = true,
messages = [],
dfd = $.Deferred();
/*
* Here is the client verification code
*/
if (!valid) {
dfd.resolve({
success: false,
errors: messages
});
} else {
form.ajaxSubmit({
dataType: "json",
success: dfd.resolve,
error : dfd.reject
});
}
return dfd.promise();
};
saveContact(row).then(function (response) {
if (response .success) {
// Client verification passed and data was saved successfully
} else {
// Client verification failed
// Output error message
}
}) .fail(function (err) {
// AJAX request failed
});

The saveContact() function first verifies the validity of the form data, and then saves the validity status in The variable is valid. If validation fails, a direct deferred will be triggered (passing a JS object containing the success status code and error information as parameters to the callback function). If the verification passes, the data is submitted to the server and the deferred object is triggered after the AJAX is successfully completed. fail() will handle 404, 500, etc. HTTP status codes that can prevent the AJAX request from completing successfully.
Non-observable Tasks
Deferreds are very useful for decoupling tasks and task processing functions, whether they are asynchronous tasks or synchronous tasks. A task may return a promise, but it may also return a string, object, or other type.
In this example, when the "Lanch Application" link is clicked for the first time, an AJAX request is sent to the server and returns the current timestamp. This timestamp will then be saved to the link's data cache. When the link is clicked again, the timestamp is simply retrieved from the cache and returned without making an AJAX request.
Copy code The code is as follows:

function startTask(element) {
var timestamp = $.data(element, 'timestamp');
if (timestamp) {
return timestamp;
} else {
return $.get('/start-task/').success( function (timestamp) {
$.data(element, 'timestamp', timestamp);
});
}
}
$('#launchApplication').bind('click ', function (event) {
event.preventDefault();
$.when(startTask(this)).done(function (timestamp) {
$('#status').html('

You first started this task on: ' timestamp '

');
});
loadApplication();
});

When $.when() finds that its first parameter has no promise function (and is therefore unobservable), it creates a new deferred object, triggers the deferred object, and returns the promise read-only object. Therefore, any unobservable task can also be passed to $.when().
One thing to note is that if an object itself has a promise function, this object cannot be used as a deferred object. jQuery determines whether an object is deferred by checking whether it has a promise function, but jQuery does not check whether the promise actually returns a usable object. Therefore the following code will error:
Copy code The code is as follows:

var obj = {
promise: function () {
// do something
}
};
$.when(obj).then(fn);

Conclusion (Conclusion)
Deferreds propose a new robust way to handle asynchronous tasks. Unlike the traditional way of organizing code into a callback function, the new deferred object allows us to bind multiple callback functions at any time (even after the task ends), and these callback functions will be called in a first-in, first-out manner. The information in this article may be difficult to digest, but once you master the use of deferred objects, you will find that organizing code that executes asynchronously will be very easy.
This article was originally written by Sansheng Shishang and first published by Blog Park. Please indicate the source when reprinting

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn