Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Adds always and chain methods to deferreds.

  • Loading branch information...
commit bb99899ca0de93dd12f5a53f409ff6f72bfcf94c 1 parent 75a4bc4
Julian Aubourg authored April 07, 2011
32  src/deferred.js
... ...
@@ -1,7 +1,7 @@
1 1
 (function( jQuery ) {
2 2
 
3 3
 var // Promise methods
4  
-	promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
  4
+	promiseMethods = "done fail isResolved isRejected promise then always chain".split( " " ),
5 5
 	// Static reference to slice
6 6
 	sliceDeferred = [].slice;
7 7
 
@@ -100,10 +100,38 @@ jQuery.extend({
100 100
 				deferred.done( doneCallbacks ).fail( failCallbacks );
101 101
 				return this;
102 102
 			},
  103
+			always: function() {
  104
+				return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
  105
+			},
103 106
 			fail: failDeferred.done,
104 107
 			rejectWith: failDeferred.resolveWith,
105 108
 			reject: failDeferred.resolve,
106 109
 			isRejected: failDeferred.isResolved,
  110
+			// Chain
  111
+			chain: function( fnDone, fnFail ) {
  112
+				return jQuery.Deferred(function( newDefer ) {
  113
+					jQuery.each( {
  114
+						done: [ fnDone, "resolve" ],
  115
+						fail: [ fnFail, "reject" ]
  116
+					}, function( handler, data ) {
  117
+						var fn = data[ 0 ],
  118
+							action = data[ 1 ],
  119
+							returned;
  120
+						if ( jQuery.isFunction( fn ) ) {
  121
+							deferred[ handler ](function() {
  122
+								returned = fn.apply( this, arguments );
  123
+								if ( jQuery.isFunction( returned.promise ) ) {
  124
+									returned.promise().then( newDefer.resolve, newDefer.reject );
  125
+								} else {
  126
+									newDefer[ action ]( returned );
  127
+								}
  128
+							});
  129
+						} else {
  130
+							deferred[ handler ]( newDefer[ action ] );
  131
+						}
  132
+					} );
  133
+				}).promise();
  134
+			},
107 135
 			// Get a promise for this deferred
108 136
 			// If obj is provided, the promise aspect is added to the object
109 137
 			promise: function( obj ) {
@@ -169,4 +197,4 @@ jQuery.extend({
169 197
 	}
170 198
 });
171 199
 
172  
-})( jQuery );
  200
+})( jQuery );
378  test/unit/deferred.js
... ...
@@ -1,153 +1,273 @@
1 1
 module("deferred", { teardown: moduleTeardown });
2 2
 
3  
-test("jQuery._Deferred()", function() {
  3
+jQuery.each( [ "", " - new operator" ], function( _, withNew ) {
4 4
 
5  
-	expect( 11 );
  5
+	function createDeferred() {
  6
+		return withNew ? new jQuery._Deferred() : jQuery._Deferred();
  7
+	}
6 8
 
7  
-	var deferred,
8  
-		object,
9  
-		test;
  9
+	test("jQuery._Deferred" + withNew, function() {
10 10
 
11  
-	deferred = jQuery._Deferred();
  11
+		expect( 11 );
12 12
 
13  
-	test = false;
  13
+		var deferred,
  14
+			object,
  15
+			test;
14 16
 
15  
-	deferred.done( function( value ) {
16  
-		equals( value , "value" , "Test pre-resolve callback" );
17  
-		test = true;
18  
-	} );
  17
+		deferred = createDeferred();
19 18
 
20  
-	deferred.resolve( "value" );
21  
-
22  
-	ok( test , "Test pre-resolve callbacks called right away" );
  19
+		test = false;
23 20
 
24  
-	test = false;
  21
+		deferred.done( function( value ) {
  22
+			equals( value , "value" , "Test pre-resolve callback" );
  23
+			test = true;
  24
+		} );
25 25
 
26  
-	deferred.done( function( value ) {
27  
-		equals( value , "value" , "Test post-resolve callback" );
28  
-		test = true;
29  
-	} );
  26
+		deferred.resolve( "value" );
30 27
 
31  
-	ok( test , "Test post-resolve callbacks called right away" );
  28
+		ok( test , "Test pre-resolve callbacks called right away" );
32 29
 
33  
-	deferred.cancel();
  30
+		test = false;
34 31
 
35  
-	test = true;
  32
+		deferred.done( function( value ) {
  33
+			equals( value , "value" , "Test post-resolve callback" );
  34
+			test = true;
  35
+		} );
36 36
 
37  
-	deferred.done( function() {
38  
-		ok( false , "Cancel was ignored" );
39  
-		test = false;
40  
-	} );
  37
+		ok( test , "Test post-resolve callbacks called right away" );
41 38
 
42  
-	ok( test , "Test cancel" );
  39
+		deferred.cancel();
43 40
 
44  
-	deferred = jQuery._Deferred().resolve();
  41
+		test = true;
45 42
 
46  
-	try {
47 43
 		deferred.done( function() {
48  
-			throw "Error";
49  
-		} , function() {
50  
-			ok( true , "Test deferred do not cancel on exception" );
  44
+			ok( false , "Cancel was ignored" );
  45
+			test = false;
51 46
 		} );
52  
-	} catch( e ) {
53  
-		strictEqual( e , "Error" , "Test deferred propagates exceptions");
54  
-		deferred.done();
55  
-	}
56 47
 
57  
-	test = "";
58  
-	deferred = jQuery._Deferred().done( function() {
  48
+		ok( test , "Test cancel" );
59 49
 
60  
-		test += "A";
  50
+		deferred = createDeferred().resolve();
61 51
 
62  
-	}, function() {
  52
+		try {
  53
+			deferred.done( function() {
  54
+				throw "Error";
  55
+			} , function() {
  56
+				ok( true , "Test deferred do not cancel on exception" );
  57
+			} );
  58
+		} catch( e ) {
  59
+			strictEqual( e , "Error" , "Test deferred propagates exceptions");
  60
+			deferred.done();
  61
+		}
63 62
 
64  
-		test += "B";
  63
+		test = "";
  64
+		deferred = createDeferred().done( function() {
65 65
 
66  
-	} ).resolve();
  66
+			test += "A";
67 67
 
68  
-	strictEqual( test , "AB" , "Test multiple done parameters" );
  68
+		}, function() {
  69
+
  70
+			test += "B";
69 71
 
70  
-	test = "";
  72
+		} ).resolve();
71 73
 
72  
-	deferred.done( function() {
  74
+		strictEqual( test , "AB" , "Test multiple done parameters" );
  75
+
  76
+		test = "";
73 77
 
74 78
 		deferred.done( function() {
75 79
 
76  
-			test += "C";
  80
+			deferred.done( function() {
  81
+
  82
+				test += "C";
77 83
 
  84
+			} );
  85
+
  86
+			test += "A";
  87
+
  88
+		}, function() {
  89
+
  90
+			test += "B";
78 91
 		} );
79 92
 
80  
-		test += "A";
  93
+		strictEqual( test , "ABC" , "Test done callbacks order" );
81 94
 
82  
-	}, function() {
  95
+		deferred = createDeferred();
83 96
 
84  
-		test += "B";
85  
-	} );
  97
+		deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) {
  98
+			ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" );
  99
+		});
  100
+
  101
+		// #8421
  102
+		deferred = createDeferred();
  103
+		deferred.resolveWith().done(function() {
  104
+			ok( true, "Test resolveWith can be called with no argument" );
  105
+		});
  106
+	});
  107
+} );
  108
+
  109
+jQuery.each( [ "", " - new operator" ], function( _, withNew ) {
  110
+
  111
+	function createDeferred( fn ) {
  112
+		return withNew ? new jQuery.Deferred( fn ) : jQuery.Deferred( fn );
  113
+	}
  114
+
  115
+	test("jQuery.Deferred" + withNew, function() {
  116
+
  117
+		expect( 8 );
  118
+
  119
+		createDeferred().resolve().then( function() {
  120
+			ok( true , "Success on resolve" );
  121
+			ok( this.isResolved(), "Deferred is resolved" );
  122
+		}, function() {
  123
+			ok( false , "Error on resolve" );
  124
+		}).always( function() {
  125
+			ok( true , "Always callback on resolve" );
  126
+		});
  127
+
  128
+		createDeferred().reject().then( function() {
  129
+			ok( false , "Success on reject" );
  130
+		}, function() {
  131
+			ok( true , "Error on reject" );
  132
+			ok( this.isRejected(), "Deferred is rejected" );
  133
+		}).always( function() {
  134
+			ok( true , "Always callback on reject" );
  135
+		});
  136
+
  137
+		createDeferred( function( defer ) {
  138
+			ok( this === defer , "Defer passed as this & first argument" );
  139
+			this.resolve( "done" );
  140
+		}).then( function( value ) {
  141
+			strictEqual( value , "done" , "Passed function executed" );
  142
+		});
  143
+	});
  144
+} );
86 145
 
87  
-	strictEqual( test , "ABC" , "Test done callbacks order" );
  146
+test( "jQuery.Deferred.chain - filtering (done)", function() {
88 147
 
89  
-	deferred = jQuery._Deferred();
  148
+	expect(3);
90 149
 
91  
-	deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) {
92  
-		ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" );
  150
+	var defer = jQuery.Deferred(),
  151
+		chained = defer.chain(function( a, b ) {
  152
+			return a * b;
  153
+		}),
  154
+		value1,
  155
+		value2,
  156
+		value3;
  157
+
  158
+	chained.done(function( result ) {
  159
+		value3 = result;
  160
+	});
  161
+
  162
+	defer.done(function( a, b ) {
  163
+		value1 = a;
  164
+		value2 = b;
93 165
 	});
94 166
 
95  
-	// #8421
96  
-	deferred = jQuery._Deferred();
97  
-	deferred.resolveWith().done(function() {
98  
-		ok( true, "Test resolveWith can be called with no argument" );
  167
+	defer.resolve( 2, 3 );
  168
+
  169
+	strictEqual( value1, 2, "first resolve value ok" );
  170
+	strictEqual( value2, 3, "second resolve value ok" );
  171
+	strictEqual( value3, 6, "result of filter ok" );
  172
+
  173
+	jQuery.Deferred().reject().chain(function() {
  174
+		ok( false, "chain should not be called on reject" );
99 175
 	});
100 176
 });
101 177
 
102  
-test("jQuery.Deferred()", function() {
  178
+test( "jQuery.Deferred.chain - filtering (fail)", function() {
  179
+
  180
+	expect(3);
103 181
 
104  
-	expect( 10 );
  182
+	var defer = jQuery.Deferred(),
  183
+		chained = defer.chain( null, function( a, b ) {
  184
+			return a * b;
  185
+		} ),
  186
+		value1,
  187
+		value2,
  188
+		value3;
105 189
 
106  
-	jQuery.Deferred( function( defer ) {
107  
-		strictEqual( this , defer , "Defer passed as this & first argument" );
108  
-		this.resolve( "done" );
109  
-	}).then( function( value ) {
110  
-		strictEqual( value , "done" , "Passed function executed" );
  190
+	chained.fail(function( result ) {
  191
+		value3 = result;
111 192
 	});
112 193
 
113  
-	jQuery.Deferred().resolve().then( function() {
114  
-		ok( true , "Success on resolve" );
115  
-	}, function() {
116  
-		ok( false , "Error on resolve" );
  194
+	defer.fail(function( a, b ) {
  195
+		value1 = a;
  196
+		value2 = b;
117 197
 	});
118 198
 
119  
-	jQuery.Deferred().reject().then( function() {
120  
-		ok( false , "Success on reject" );
121  
-	}, function() {
122  
-		ok( true , "Error on reject" );
  199
+	defer.reject( 2, 3 );
  200
+
  201
+	strictEqual( value1, 2, "first reject value ok" );
  202
+	strictEqual( value2, 3, "second reject value ok" );
  203
+	strictEqual( value3, 6, "result of filter ok" );
  204
+
  205
+	jQuery.Deferred().resolve().chain( null, function() {
  206
+		ok( false, "chain should not be called on resolve" );
  207
+	} );
  208
+});
  209
+
  210
+test( "jQuery.Deferred.chain - deferred (done)", function() {
  211
+
  212
+	expect(3);
  213
+
  214
+	var defer = jQuery.Deferred(),
  215
+		chained = defer.chain(function( a, b ) {
  216
+			return jQuery.Deferred(function( defer ) {
  217
+				defer.reject( a * b );
  218
+			});
  219
+		}),
  220
+		value1,
  221
+		value2,
  222
+		value3;
  223
+
  224
+	chained.fail(function( result ) {
  225
+		value3 = result;
123 226
 	});
124 227
 
125  
-	( new jQuery.Deferred( function( defer ) {
126  
-		strictEqual( this , defer , "Defer passed as this & first argument (new)" );
127  
-		this.resolve( "done" );
128  
-	}) ).then( function( value ) {
129  
-		strictEqual( value , "done" , "Passed function executed (new)" );
  228
+	defer.done(function( a, b ) {
  229
+		value1 = a;
  230
+		value2 = b;
130 231
 	});
131 232
 
132  
-	( new jQuery.Deferred() ).resolve().then( function() {
133  
-		ok( true , "Success on resolve (new)" );
134  
-	}, function() {
135  
-		ok( false , "Error on resolve (new)" );
  233
+	defer.resolve( 2, 3 );
  234
+
  235
+	strictEqual( value1, 2, "first resolve value ok" );
  236
+	strictEqual( value2, 3, "second resolve value ok" );
  237
+	strictEqual( value3, 6, "result of filter ok" );
  238
+});
  239
+
  240
+test( "jQuery.Deferred.chain - deferred (fail)", function() {
  241
+
  242
+	expect(3);
  243
+
  244
+	var defer = jQuery.Deferred(),
  245
+		chained = defer.chain( null, function( a, b ) {
  246
+			return jQuery.Deferred(function( defer ) {
  247
+				defer.resolve( a * b );
  248
+			});
  249
+		} ),
  250
+		value1,
  251
+		value2,
  252
+		value3;
  253
+
  254
+	chained.done(function( result ) {
  255
+		value3 = result;
136 256
 	});
137 257
 
138  
-	( new jQuery.Deferred() ).reject().then( function() {
139  
-		ok( false , "Success on reject (new)" );
140  
-	}, function() {
141  
-		ok( true , "Error on reject (new)" );
  258
+	defer.fail(function( a, b ) {
  259
+		value1 = a;
  260
+		value2 = b;
142 261
 	});
143 262
 
144  
-	var tmp = jQuery.Deferred();
  263
+	defer.reject( 2, 3 );
145 264
 
146  
-	strictEqual( tmp.promise() , tmp.promise() , "Test deferred always return same promise" );
147  
-	strictEqual( tmp.promise() , tmp.promise().promise() , "Test deferred's promise always return same promise as deferred" );
  265
+	strictEqual( value1, 2, "first reject value ok" );
  266
+	strictEqual( value2, 3, "second reject value ok" );
  267
+	strictEqual( value3, 6, "result of filter ok" );
148 268
 });
149 269
 
150  
-test("jQuery.when()", function() {
  270
+test( "jQuery.when" , function() {
151 271
 
152 272
 	expect( 23 );
153 273
 
@@ -166,57 +286,63 @@ test("jQuery.when()", function() {
166 286
 
167 287
 	} , function( message , value ) {
168 288
 
169  
-		ok( jQuery.isFunction( jQuery.when( value ).then( function( resolveValue ) {
  289
+		ok( jQuery.isFunction( jQuery.when( value ).done(function( resolveValue ) {
170 290
 			strictEqual( resolveValue , value , "Test the promise was resolved with " + message );
171  
-		} ).promise ) , "Test " + message + " triggers the creation of a new Promise" );
  291
+		}).promise ) , "Test " + message + " triggers the creation of a new Promise" );
172 292
 
173 293
 	} );
174 294
 
175  
-	ok( jQuery.isFunction( jQuery.when().then( function( resolveValue ) {
  295
+	ok( jQuery.isFunction( jQuery.when().done(function( resolveValue ) {
176 296
 		strictEqual( resolveValue , undefined , "Test the promise was resolved with no parameter" );
177  
-	} ).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" );
  297
+	}).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" );
178 298
 
179 299
 	var cache, i;
180 300
 
181 301
 	for( i = 1 ; i < 4 ; i++ ) {
182 302
 		jQuery.when( cache || jQuery.Deferred( function() {
183 303
 			this.resolve( i );
184  
-		}) ).then( function( value ) {
  304
+		}) ).done(function( value ) {
185 305
 			strictEqual( value , 1 , "Function executed" + ( i > 1 ? " only once" : "" ) );
186 306
 			cache = value;
187  
-		}, function() {
188  
-			ok( false , "Fail called" );
189 307
 		});
190 308
 	}
191 309
 });
192 310
 
193  
-test("jQuery.when() - joined", function() {
194  
-
195  
-	expect(8);
196  
-
197  
-	jQuery.when( 1, 2, 3 ).done( function( a, b, c ) {
198  
-		strictEqual( a , 1 , "Test first param is first resolved value - non-observables" );
199  
-		strictEqual( b , 2 , "Test second param is second resolved value - non-observables" );
200  
-		strictEqual( c , 3 , "Test third param is third resolved value - non-observables" );
201  
-	}).fail( function() {
202  
-		ok( false , "Test the created deferred was resolved - non-observables");
203  
-	});
204  
-
205  
-	var successDeferred = jQuery.Deferred().resolve( 1 , 2 , 3 ),
206  
-		errorDeferred = jQuery.Deferred().reject( "error" , "errorParam" );
207  
-
208  
-	jQuery.when( 1 , successDeferred , 3 ).done( function( a, b, c ) {
209  
-		strictEqual( a , 1 , "Test first param is first resolved value - resolved observable" );
210  
-		same( b , [ 1 , 2 , 3 ] , "Test second param is second resolved value - resolved observable" );
211  
-		strictEqual( c , 3 , "Test third param is third resolved value - resolved observable" );
212  
-	}).fail( function() {
213  
-		ok( false , "Test the created deferred was resolved - resolved observable");
214  
-	});
215  
-
216  
-	jQuery.when( 1 , errorDeferred , 3 ).done( function() {
217  
-		ok( false , "Test the created deferred was rejected - rejected observable");
218  
-	}).fail( function( error , errorParam ) {
219  
-		strictEqual( error , "error" , "Test first param is first rejected value - rejected observable" );
220  
-		strictEqual( errorParam , "errorParam" , "Test second param is second rejected value - rejected observable" );
221  
-	});
  311
+test("jQuery.when - joined", function() {
  312
+
  313
+	expect(25);
  314
+
  315
+	var deferreds = {
  316
+			value: 1,
  317
+			success: jQuery.Deferred().resolve( 1 ),
  318
+			error: jQuery.Deferred().reject( 0 ),
  319
+			futureSuccess: jQuery.Deferred(),
  320
+			futureError: jQuery.Deferred()
  321
+		},
  322
+		willSucceed = {
  323
+			value: true,
  324
+			success: true,
  325
+			error: false,
  326
+			futureSuccess: true,
  327
+			futureError: false
  328
+		};
  329
+
  330
+	jQuery.each( deferreds, function( id1, defer1 ) {
  331
+		jQuery.each( deferreds, function( id2, defer2 ) {
  332
+			var shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ],
  333
+				expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ],
  334
+				code = id1 + "/" + id2;
  335
+			jQuery.when( defer1, defer2 ).done(function( a, b ) {
  336
+				if ( shouldResolve ) {
  337
+					same( [ a, b ], expected, code + " => resolve" );
  338
+				}
  339
+			}).fail(function( a, b ) {
  340
+				if ( !shouldResolve ) {
  341
+					same( [ a, b ], expected, code + " => resolve" );
  342
+				}
  343
+			});
  344
+		} );
  345
+	} );
  346
+	deferreds.futureSuccess.resolve( 1 );
  347
+	deferreds.futureError.reject( 0 );
222 348
 });

0 notes on commit bb99899

Please sign in to comment.
Something went wrong with that request. Please try again.