From 54d965ffa50fcc308721d370f952251d3da3e017 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Tue, 28 Dec 2010 04:13:44 +0100 Subject: [PATCH] Introduced a new promise method on deferreds that returns an immutable object (exposing then, fail, isResolved, isRejected and promise itself only). Remove $.isDeferred and moved logic directly into $.when. Made sure $.when returns a promise by using promise(). Used promise() in ajax code too. --- src/ajax.js | 7 +++--- src/core.js | 30 ++++++++++++------------ test/unit/core.js | 58 ++++++++++++++++++++++------------------------- 3 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index 40524fb4..8c02f2b7 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -489,9 +489,10 @@ jQuery.extend({ } } - // Attach deferreds - jXHR.success = jXHR.then = deferred.then; - jXHR.error = jXHR.fail = deferred.fail; + // Attach deferreds + deferred.promise( jXHR ); + jXHR.success = jXHR.then; + jXHR.error = jXHR.fail; jXHR.complete = completeDeferred.then; // Remove hash character (#7531: and string promotion) diff --git a/src/core.js b/src/core.js index eb0c1c8a..07666d92 100644 --- a/src/core.js +++ b/src/core.js @@ -78,7 +78,7 @@ var jQuery = function( selector, context ) { class2type = {}, // Marker for deferred - deferredMarker = []; + promiseMarker = []; jQuery.fn = jQuery.prototype = { init: function( selector, context ) { @@ -896,9 +896,6 @@ jQuery.extend({ } }; - // Add the deferred marker - deferred.then._ = deferredMarker; - return deferred; }, @@ -916,7 +913,16 @@ jQuery.extend({ fail: errorDeferred.then, fireReject: errorDeferred.fire, reject: errorDeferred.resolve, - isRejected: errorDeferred.isResolved + isRejected: errorDeferred.isResolved, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + obj = obj || {}; + for ( var i in { then:1 , fail:1 , isResolved:1 , isRejected:1 , promise:1 } ) { + obj[ i ] = deferred[ i ]; + } + return obj; + } } ); @@ -924,6 +930,9 @@ jQuery.extend({ delete deferred.cancel; delete deferred.isCancelled; + // Add promise marker + deferred.promise._ = promiseMarker; + // Make sure only one callback list will be used deferred.then( errorDeferred.cancel ).fail( successCancel ); @@ -935,17 +944,12 @@ jQuery.extend({ return deferred; }, - // Check if an object is a deferred - isDeferred: function( object ) { - return !!( object && object.then && object.then._ === deferredMarker ); - }, - // Deferred helper when: function( object ) { - object = jQuery.isDeferred( object ) ? + object = object && object.promise && object.promise._ === promiseMarker ? object : jQuery.Deferred().resolve( object ); - return object; + return object.promise(); }, // Use of jQuery.browser is frowned upon. @@ -966,9 +970,7 @@ jQuery.extend({ }); // Create readyList deferred -// also force $.fn.ready to be recognized as a defer readyList = jQuery._Deferred(); -jQuery.fn.ready._ = deferredMarker; // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { diff --git a/test/unit/core.js b/test/unit/core.js index e0938b68..1cd41a67 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1022,42 +1022,38 @@ test("jQuery.Deferred()", function() { }); }); -test("jQuery.isDeferred()", function() { - - expect( 10 ); - - var object1 = { then: function() { return this; } }, - object2 = { then: function() { return this; } }; - - object2.then._ = []; - - // The use case that we want to match - ok(jQuery.isDeferred(jQuery._Deferred()), "Simple deferred"); - ok(jQuery.isDeferred(jQuery.Deferred()), "Failable deferred"); - - // Some other objects - ok(!jQuery.isDeferred(object1), "Object with then & no marker"); - ok(!jQuery.isDeferred(object2), "Object with then & marker"); - - // Not objects shouldn't be matched - ok(!jQuery.isDeferred(""), "string"); - ok(!jQuery.isDeferred(0) && !jQuery.isDeferred(1), "number"); - ok(!jQuery.isDeferred(true) && !jQuery.isDeferred(false), "boolean"); - ok(!jQuery.isDeferred(null), "null"); - ok(!jQuery.isDeferred(undefined), "undefined"); - - object1 = {custom: jQuery._Deferred().then}; - - ok(!jQuery.isDeferred(object1) , "custom method name not found automagically"); -}); - test("jQuery.when()", function() { - expect( 2 ); + expect( 14 ); + + var fakeDeferred = { then: function() { return this; } }; + + fakeDeferred.then._ = []; + + // Some other objects + jQuery.each( { + + "Object with then & no marker": { then: jQuery.noop }, + "Object with then & marker": fakeDeferred, + "string 1/2": "", + "string 2/2": "some string", + "number 1/2": 0, + "number 2/2": 1, + "boolean 1/2": true, + "boolean 2/2": false, + "null": null, + "undefined": undefined, + "custom method name not found automagically": {custom: jQuery._Deferred().then} + + } , function( message , value ) { + + notStrictEqual( jQuery.when( value ) , value , message ); + + } ); var cache, i; - for( i = 1 ; i < 3 ; i++ ) { + for( i = 1 ; i < 4 ; i++ ) { jQuery.when( cache || jQuery.Deferred( function() { this.resolve( i ); }) ).then( function( value ) {