Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 1ae9ae5

Browse files
committed
refactor($q): separate Promise from Deferred
BREAKING CHANGE: The Deferred object returned by $q.defer() previously delegated methods to those on Deferred.prototype. If Deferred.prototype was modified these methods would reflect that. This change removes that delegation and no longer uses methods on Deferred.prototype. Modifying methods on Deferred.prototype will no longer have an effect.
1 parent 7bc71ad commit 1ae9ae5

File tree

1 file changed

+97
-103
lines changed

1 file changed

+97
-103
lines changed

src/ng/q.js

+97-103
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,18 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
299299
* @returns {Deferred} Returns a new instance of deferred.
300300
*/
301301
function defer() {
302-
var d = new Deferred();
303-
//Necessary to support unbound execution :/
304-
d.resolve = simpleBind(d, d.resolve);
305-
d.reject = simpleBind(d, d.reject);
306-
d.notify = simpleBind(d, d.notify);
307-
return d;
302+
return new Deferred();
308303
}
309304

305+
function Deferred() {
306+
var promise = this.promise = new Promise();
307+
//Non prototype methods necessary to support unbound execution :/
308+
this.resolve = function(val) { resolvePromise(promise, val); };
309+
this.reject = function(reason) { rejectPromise(promise, reason); };
310+
this.notify = function(progress) { notifyPromise(promise, progress); };
311+
}
312+
313+
310314
function Promise() {
311315
this.$$state = { status: 0 };
312316
}
@@ -316,13 +320,13 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
316320
if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
317321
return this;
318322
}
319-
var result = new Deferred();
323+
var result = new Promise();
320324

321325
this.$$state.pending = this.$$state.pending || [];
322326
this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
323327
if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
324328

325-
return result.promise;
329+
return result;
326330
},
327331

328332
'catch': function(callback) {
@@ -338,34 +342,27 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
338342
}
339343
});
340344

341-
//Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
342-
function simpleBind(context, fn) {
343-
return function(value) {
344-
fn.call(context, value);
345-
};
346-
}
347-
348345
function processQueue(state) {
349-
var fn, deferred, pending;
346+
var fn, promise, pending;
350347

351348
pending = state.pending;
352349
state.processScheduled = false;
353350
state.pending = undefined;
354351
try {
355352
for (var i = 0, ii = pending.length; i < ii; ++i) {
356353
state.pur = true;
357-
deferred = pending[i][0];
354+
promise = pending[i][0];
358355
fn = pending[i][state.status];
359356
try {
360357
if (isFunction(fn)) {
361-
deferred.resolve(fn(state.value));
358+
resolvePromise(promise, fn(state.value));
362359
} else if (state.status === 1) {
363-
deferred.resolve(state.value);
360+
resolvePromise(promise, state.value);
364361
} else {
365-
deferred.reject(state.value);
362+
rejectPromise(promise, state.value);
366363
}
367364
} catch (e) {
368-
deferred.reject(e);
365+
rejectPromise(promise, e);
369366
}
370367
}
371368
} finally {
@@ -401,83 +398,80 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
401398
nextTick(function() { processQueue(state); });
402399
}
403400

404-
function Deferred() {
405-
this.promise = new Promise();
401+
function resolvePromise(promise, val) {
402+
if (promise.$$state.status) return;
403+
if (val === promise) {
404+
$$reject(promise, $qMinErr(
405+
'qcycle',
406+
'Expected promise to be resolved with value other than itself \'{0}\'',
407+
val));
408+
} else {
409+
$$resolve(promise, val);
410+
}
411+
406412
}
407413

408-
extend(Deferred.prototype, {
409-
resolve: function(val) {
410-
if (this.promise.$$state.status) return;
411-
if (val === this.promise) {
412-
this.$$reject($qMinErr(
413-
'qcycle',
414-
'Expected promise to be resolved with value other than itself \'{0}\'',
415-
val));
414+
function $$resolve(promise, val) {
415+
var then;
416+
var done = false;
417+
try {
418+
if ((isObject(val) || isFunction(val))) then = val && val.then;
419+
if (isFunction(then)) {
420+
promise.$$state.status = -1;
421+
then.call(val, doResolve, doReject, doNotify);
416422
} else {
417-
this.$$resolve(val);
418-
}
419-
},
420-
421-
$$resolve: function(val) {
422-
var then;
423-
var that = this;
424-
var done = false;
425-
try {
426-
if (isObject(val) || isFunction(val)) then = val.then;
427-
if (isFunction(then)) {
428-
this.promise.$$state.status = -1;
429-
then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
430-
} else {
431-
this.promise.$$state.value = val;
432-
this.promise.$$state.status = 1;
433-
scheduleProcessQueue(this.promise.$$state);
434-
}
435-
} catch (e) {
436-
rejectPromise(e);
423+
promise.$$state.value = val;
424+
promise.$$state.status = 1;
425+
scheduleProcessQueue(promise.$$state);
437426
}
427+
} catch (e) {
428+
doReject(e);
429+
}
438430

439-
function resolvePromise(val) {
440-
if (done) return;
441-
done = true;
442-
that.$$resolve(val);
443-
}
444-
function rejectPromise(val) {
445-
if (done) return;
446-
done = true;
447-
that.$$reject(val);
448-
}
449-
},
431+
function doResolve(val) {
432+
if (done) return;
433+
done = true;
434+
$$resolve(promise, val);
435+
}
436+
function doReject(val) {
437+
if (done) return;
438+
done = true;
439+
$$reject(promise, val);
440+
}
441+
function doNotify(progress) {
442+
notifyPromise(promise, progress);
443+
}
444+
}
450445

451-
reject: function(reason) {
452-
if (this.promise.$$state.status) return;
453-
this.$$reject(reason);
454-
},
446+
function rejectPromise(promise, reason) {
447+
if (promise.$$state.status) return;
448+
$$reject(promise, reason);
449+
}
455450

456-
$$reject: function(reason) {
457-
this.promise.$$state.value = reason;
458-
this.promise.$$state.status = 2;
459-
scheduleProcessQueue(this.promise.$$state);
460-
},
451+
function $$reject(promise, reason) {
452+
promise.$$state.value = reason;
453+
promise.$$state.status = 2;
454+
scheduleProcessQueue(promise.$$state);
455+
}
461456

462-
notify: function(progress) {
463-
var callbacks = this.promise.$$state.pending;
464-
465-
if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
466-
nextTick(function() {
467-
var callback, result;
468-
for (var i = 0, ii = callbacks.length; i < ii; i++) {
469-
result = callbacks[i][0];
470-
callback = callbacks[i][3];
471-
try {
472-
result.notify(isFunction(callback) ? callback(progress) : progress);
473-
} catch (e) {
474-
exceptionHandler(e);
475-
}
457+
function notifyPromise(promise, progress) {
458+
var callbacks = promise.$$state.pending;
459+
460+
if ((promise.$$state.status <= 0) && callbacks && callbacks.length) {
461+
nextTick(function() {
462+
var callback, result;
463+
for (var i = 0, ii = callbacks.length; i < ii; i++) {
464+
result = callbacks[i][0];
465+
callback = callbacks[i][3];
466+
try {
467+
notifyPromise(result, isFunction(callback) ? callback(progress) : progress);
468+
} catch (e) {
469+
exceptionHandler(e);
476470
}
477-
});
478-
}
471+
}
472+
});
479473
}
480-
});
474+
}
481475

482476
/**
483477
* @ngdoc method
@@ -516,9 +510,9 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
516510
* @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
517511
*/
518512
function reject(reason) {
519-
var result = new Deferred();
520-
result.reject(reason);
521-
return result.promise;
513+
var result = new Promise();
514+
rejectPromise(result, reason);
515+
return result;
522516
}
523517

524518
function handleCallback(value, resolver, callback) {
@@ -556,9 +550,9 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
556550

557551

558552
function when(value, callback, errback, progressBack) {
559-
var result = new Deferred();
560-
result.resolve(value);
561-
return result.promise.then(callback, errback, progressBack);
553+
var result = new Promise();
554+
resolvePromise(result, value);
555+
return result.then(callback, errback, progressBack);
562556
}
563557

564558
/**
@@ -594,25 +588,25 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
594588
*/
595589

596590
function all(promises) {
597-
var deferred = new Deferred(),
591+
var result = new Promise(),
598592
counter = 0,
599593
results = isArray(promises) ? [] : {};
600594

601595
forEach(promises, function(promise, key) {
602596
counter++;
603597
when(promise).then(function(value) {
604598
results[key] = value;
605-
if (!(--counter)) deferred.resolve(results);
599+
if (!(--counter)) resolvePromise(result, results);
606600
}, function(reason) {
607-
deferred.reject(reason);
601+
rejectPromise(result, reason);
608602
});
609603
});
610604

611605
if (counter === 0) {
612-
deferred.resolve(results);
606+
resolvePromise(result, results);
613607
}
614608

615-
return deferred.promise;
609+
return result;
616610
}
617611

618612
/**
@@ -644,19 +638,19 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
644638
throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver);
645639
}
646640

647-
var deferred = new Deferred();
641+
var promise = new Promise();
648642

649643
function resolveFn(value) {
650-
deferred.resolve(value);
644+
resolvePromise(promise, value);
651645
}
652646

653647
function rejectFn(reason) {
654-
deferred.reject(reason);
648+
rejectPromise(promise, reason);
655649
}
656650

657651
resolver(resolveFn, rejectFn);
658652

659-
return deferred.promise;
653+
return promise;
660654
}
661655

662656
// Let's make the instanceof operator work for promises, so that

0 commit comments

Comments
 (0)