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();
}
});