1 | define([
|
2 | "./has",
|
3 | "./_base/lang",
|
4 | "./errors/CancelError",
|
5 | "./promise/Promise",
|
6 | "./has!config-deferredInstrumentation?./promise/instrumentation"
|
7 | ], function(has, lang, CancelError, Promise, instrumentation){
|
8 | "use strict";
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | var PROGRESS = 0,
|
14 | RESOLVED = 1,
|
15 | REJECTED = 2;
|
16 | var FULFILLED_ERROR_MESSAGE = "This deferred has already been fulfilled.";
|
17 |
|
18 | var freezeObject = Object.freeze || function(){};
|
19 |
|
20 | var signalWaiting = function(waiting, type, result, rejection, deferred){
|
21 | if(has("config-deferredInstrumentation")){
|
22 | if(type === REJECTED && Deferred.instrumentRejected && waiting.length === 0){
|
23 | Deferred.instrumentRejected(result, false, rejection, deferred);
|
24 | }
|
25 | }
|
26 |
|
27 | for(var i = 0; i < waiting.length; i++){
|
28 | signalListener(waiting[i], type, result, rejection);
|
29 | }
|
30 | };
|
31 |
|
32 | var signalListener = function(listener, type, result, rejection){
|
33 | var func = listener[type];
|
34 | var deferred = listener.deferred;
|
35 | if(func){
|
36 | try{
|
37 | var newResult = func(result);
|
38 | if(type === PROGRESS){
|
39 | if(typeof newResult !== "undefined"){
|
40 | signalDeferred(deferred, type, newResult);
|
41 | }
|
42 | }else{
|
43 | if(newResult && typeof newResult.then === "function"){
|
44 | listener.cancel = newResult.cancel;
|
45 | newResult.then(
|
46 |
|
47 | makeDeferredSignaler(deferred, RESOLVED),
|
48 | makeDeferredSignaler(deferred, REJECTED),
|
49 | makeDeferredSignaler(deferred, PROGRESS));
|
50 | return;
|
51 | }
|
52 | signalDeferred(deferred, RESOLVED, newResult);
|
53 | }
|
54 | }catch(error){
|
55 | signalDeferred(deferred, REJECTED, error);
|
56 | }
|
57 | }else{
|
58 | signalDeferred(deferred, type, result);
|
59 | }
|
60 |
|
61 | if(has("config-deferredInstrumentation")){
|
62 | if(type === REJECTED && Deferred.instrumentRejected){
|
63 | Deferred.instrumentRejected(result, !!func, rejection, deferred.promise);
|
64 | }
|
65 | }
|
66 | };
|
67 |
|
68 | var makeDeferredSignaler = function(deferred, type){
|
69 | return function(value){
|
70 | signalDeferred(deferred, type, value);
|
71 | };
|
72 | };
|
73 |
|
74 | var signalDeferred = function(deferred, type, result){
|
75 | if(!deferred.isCanceled()){
|
76 | switch(type){
|
77 | case PROGRESS:
|
78 | deferred.progress(result);
|
79 | break;
|
80 | case RESOLVED:
|
81 | deferred.resolve(result);
|
82 | break;
|
83 | case REJECTED:
|
84 | deferred.reject(result);
|
85 | break;
|
86 | }
|
87 | }
|
88 | };
|
89 |
|
90 | var Deferred = function(canceler){
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 | var promise = this.promise = new Promise();
|
108 |
|
109 | var deferred = this;
|
110 | var fulfilled, result, rejection;
|
111 | var canceled = false;
|
112 | var waiting = [];
|
113 |
|
114 | if(has("config-deferredInstrumentation") && Error.captureStackTrace){
|
115 | Error.captureStackTrace(deferred, Deferred);
|
116 | Error.captureStackTrace(promise, Deferred);
|
117 | }
|
118 |
|
119 | this.isResolved = promise.isResolved = function(){
|
120 |
|
121 |
|
122 |
|
123 |
|
124 | return fulfilled === RESOLVED;
|
125 | };
|
126 |
|
127 | this.isRejected = promise.isRejected = function(){
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | return fulfilled === REJECTED;
|
133 | };
|
134 |
|
135 | this.isFulfilled = promise.isFulfilled = function(){
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | return !!fulfilled;
|
141 | };
|
142 |
|
143 | this.isCanceled = promise.isCanceled = function(){
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | return canceled;
|
149 | };
|
150 |
|
151 | this.progress = function(update, strict){
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | if(!fulfilled){
|
167 | signalWaiting(waiting, PROGRESS, update, null, deferred);
|
168 | return promise;
|
169 | }else if(strict === true){
|
170 | throw new Error(FULFILLED_ERROR_MESSAGE);
|
171 | }else{
|
172 | return promise;
|
173 | }
|
174 | };
|
175 |
|
176 | this.resolve = function(value, strict){
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 | if(!fulfilled){
|
190 |
|
191 |
|
192 | signalWaiting(waiting, fulfilled = RESOLVED, result = value, null, deferred);
|
193 | waiting = null;
|
194 | return promise;
|
195 | }else if(strict === true){
|
196 | throw new Error(FULFILLED_ERROR_MESSAGE);
|
197 | }else{
|
198 | return promise;
|
199 | }
|
200 | };
|
201 |
|
202 | var reject = this.reject = function(error, strict){
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 | if(!fulfilled){
|
216 | if(has("config-deferredInstrumentation") && Error.captureStackTrace){
|
217 | Error.captureStackTrace(rejection = {}, reject);
|
218 | }
|
219 | signalWaiting(waiting, fulfilled = REJECTED, result = error, rejection, deferred);
|
220 | waiting = null;
|
221 | return promise;
|
222 | }else if(strict === true){
|
223 | throw new Error(FULFILLED_ERROR_MESSAGE);
|
224 | }else{
|
225 | return promise;
|
226 | }
|
227 | };
|
228 |
|
229 | this.then = promise.then = function(callback, errback, progback){
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 | var listener = [progback, callback, errback];
|
249 |
|
250 |
|
251 | listener.cancel = promise.cancel;
|
252 | listener.deferred = new Deferred(function(reason){
|
253 |
|
254 |
|
255 | return listener.cancel && listener.cancel(reason);
|
256 | });
|
257 | if(fulfilled && !waiting){
|
258 | signalListener(listener, fulfilled, result, rejection);
|
259 | }else{
|
260 | waiting.push(listener);
|
261 | }
|
262 | return listener.deferred.promise;
|
263 | };
|
264 |
|
265 | this.cancel = promise.cancel = function(reason, strict){
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 | if(!fulfilled){
|
284 |
|
285 | if(canceler){
|
286 | var returnedReason = canceler(reason);
|
287 | reason = typeof returnedReason === "undefined" ? reason : returnedReason;
|
288 | }
|
289 | canceled = true;
|
290 | if(!fulfilled){
|
291 |
|
292 | if(typeof reason === "undefined"){
|
293 | reason = new CancelError();
|
294 | }
|
295 | reject(reason);
|
296 | return reason;
|
297 | }else if(fulfilled === REJECTED && result === reason){
|
298 | return reason;
|
299 | }
|
300 | }else if(strict === true){
|
301 | throw new Error(FULFILLED_ERROR_MESSAGE);
|
302 | }
|
303 | };
|
304 |
|
305 | freezeObject(promise);
|
306 | };
|
307 |
|
308 | Deferred.prototype.toString = function(){
|
309 |
|
310 |
|
311 |
|
312 | return "[object Deferred]";
|
313 | };
|
314 |
|
315 | if(instrumentation){
|
316 | instrumentation(Deferred);
|
317 | }
|
318 |
|
319 | return Deferred;
|
320 | });
|