deferred.promise() and .promise()
The syntax of these two APIs is almost the same, but there are big differences. deferred.promise() is a method of Deferred instance, which returns a Deferred.Promise instance. A Deferred.Promise object can be understood as a view of the deferred object. It only contains a set of methods of the deferred object, including: done(), then(), fail(), isResolved(), isRejected(), always() ,These methods can only observe the state of a deferred, but cannot change the internal state of the deferred object. This is very suitable for API encapsulation. For example, the holder of a deferred object can control the state of the deferred state (resolved or rejected) according to his own needs, but he can return the Promise object of this deferred object to other observers, and the observers can only observe the changes in the state. The corresponding callback function, but cannot change the internal state of the deferred object, thus providing good isolation protection.
deferred.promise()
$(function(){ // var deferred = $.Deferred(); var promise = deferred.promise(); var doSomething = function(promise) { promise.done(function(){ alert('deferred resolved.'); }); }; deferred.resolve(); doSomething(promise); })
// Existing object var obj = { hello: function( name ) { alert( "Hello " + name ); } }, // Create a Deferred defer = $.Deferred(); // Set object as a promise defer.promise( obj ); // Resolve the deferred defer.resolve( "John" ); // Use the object as a Promise obj.done(function( name ) { this.hello( name ); // will alert "Hello John" }).hello( "Karl" ); // will alert "Hello Karl"
deferred.promise() just prevents other code from changing the state of this deferred object. It can be understood that the deferred promise object returned by the deferred.promise() method does not have resolve, reject, progress, resolveWith, rejectWith, progressWith methods that can change the state. You can only use done, then, fail and other methods to add handlers. Or judge the status.
deferred.promise() cannot change the state of the deferred object, nor does it ensure that the current state remains unchanged. It only ensures that you cannot change the state of the deferred object through the deferred promise object returned by deferred.promise(). If we directly return dtd here, it will still work. The .done processing function will still wait until dtd.resolve() before executing it.
For the specific example in that blog, if we change the code to the following form:
var dtd = $.Deferred(); // 新建一个deferred对象 var wait = function(dtd){ var tasks = function(){ alert("执行完毕!"); dtd.resolve(); // 改变deferred对象的执行状态 }; setTimeout(tasks,5000); return dtd; }; $.when(wait(dtd)) .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出错啦!"); });
The result of this execution is the same as the result of returning dtd.promise previously.
What’s the difference? If we change the code of $.when to this:
var d = wait(dtd); $.when(d) .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出错啦!"); }); d.resolve();
We will find that alert("Haha, successful!") will be executed immediately, but "execution completed" will take 5 seconds to pop up.
But if our wait function finally returns dtd.promise() here d.resolve() will report an error because the object d does not have a resolve() method.
Similarly if we change the code to:
var dtd = $.Deferred(); // 新建一个deferred对象 var wait = function(dtd){ var tasks = function(){ alert("执行完毕!"); dtd.resolve(); // 改变deferred对象的执行状态 }; setTimeout(tasks,5000); return dtd.promise(); }; dtd.resolve(); $.when( wait(dtd)) .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出错啦!"); });
We can also find that alert("Haha, successful!") will be executed immediately, because the deferred object dtd has been resolved() before being passed into wait, and once the deferred object is resolved or rejected, The status will not change.
Then we change the $.wait code to:
$.when( wait(dtd)) .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出错啦!"); }); dtd.resolve();
We will also find that alert("Haha, successful!"); is executed immediately. Although when wait(dtd) is executed, dtd has not been resolved, and the wait method returns dtd.promise(), but The original deferred object dtd is exposed to the outside, and we can still change its state from the outside.
So, if we really don’t want other code to change the state of the deferred object inside the wait method, then we should write it like this:
var wait = function(){ var dtd = $.Deferred(); // 新建一个deferred对象 var tasks = function(){ alert("执行完毕!"); dtd.resolve(); // 改变deferred对象的执行状态 }; setTimeout(tasks,5000); return dtd.promise(); }; $.when( wait()) .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出错啦!"); });
That is, do not expose deferred directly, and finally return deferred.promise(), so that other code can only add handler.
.promise()
First of all, this is not a method of Deferred instances! This method is a method of jQuery instance. This method is used to return a Promise object after a set of types of actions (such as animation) is completed, for the event listener to monitor its status and execute the corresponding processing function.
This method accepts two optional parameters: .promise( [type,] [target] )
type: the type of queue, the default value is fx, fx is the animation of jQuery object.
targetObject: the object to be assigned Promise behavior,
These two parameters are optional. The first parameter (me) currently has no other value type found except fx. Therefore, it is generally used to monitor animations and do some operations after the animation is completed.
Example: Directly returning a resolved state promise object without animation effect
var div = $( "<div />" ); div.promise().done(function( arg1 ) { // 将会被马上触发 alert( this === div && arg1 === div ); });
Example: Trigger the done() listening function after all animation effects are completed
<!DOCTYPE html> <html> <head> <style> div { height: 50px; width: 50px; float: left; margin-right: 10px; display: none; background-color: #090; } </style> <script src="http://code.jquery.com/jquery-latest.js"></script> </head> <body> <button>Go</button> <p>Ready...</p> <div></div> <div></div> <div></div> <div></div> <script> $("button").bind( "click", function() { $("p").append( "Started..."); //每个div执行动画效果 $("div").each(function( i ) { $( this ).fadeIn().fadeOut( 1000 * (i+1) ); }); //$("div")包含一组div,在所有的div都完成自己的动画效果后触发done()函数 $( "div" ).promise().done(function() { $( "p" ).append( " Finished! " ); }); }); </script> </body> </html>