Skip to content

Commit 0ba14e1

Browse files
yihanghopetebacondarwin
authored andcommitted
feat($q): implement $q.race
Implement $q.race. $q.race takes in an array or hash of promises and returns a promise that resolves or rejects as soon as one of those promises resolves or rejects, with the value or reason from that promise. Closes angular#12929 Closes angular#14757
1 parent d9b42dd commit 0ba14e1

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

src/ng/q.js

+25
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,30 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
637637
return deferred.promise;
638638
}
639639

640+
/**
641+
* @ngdoc method
642+
* @name $q#race
643+
* @kind function
644+
*
645+
* @description
646+
* Returns a promise that resolves or rejects as soon as one of those promises
647+
* resolves or rejects, with the value or reason from that promise.
648+
*
649+
* @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
650+
* @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`
651+
* resolves or rejects, with the value or reason from that promise.
652+
*/
653+
654+
function race(promises) {
655+
var deferred = defer();
656+
657+
forEach(promises, function(promise) {
658+
when(promise).then(deferred.resolve, deferred.reject);
659+
});
660+
661+
return deferred.promise;
662+
}
663+
640664
var $Q = function Q(resolver) {
641665
if (!isFunction(resolver)) {
642666
throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
@@ -666,6 +690,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
666690
$Q.when = when;
667691
$Q.resolve = resolve;
668692
$Q.all = all;
693+
$Q.race = race;
669694

670695
return $Q;
671696
}

test/ng/qSpec.js

+72
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,78 @@ describe('q', function() {
19861986
});
19871987
});
19881988

1989+
describe('race (array)', function() {
1990+
it('should do nothing if given an empty array', function() {
1991+
q.race([]).then(success(), error());
1992+
expect(mockNextTick.queue.length).toBe(0);
1993+
expect(logStr()).toBe('');
1994+
});
1995+
1996+
it('should resolve as soon as the first promise is settled by resolution', function() {
1997+
var deferred1 = defer(),
1998+
deferred2 = defer();
1999+
2000+
q.race([promise, deferred1.promise, deferred2.promise]).then(success(), error());
2001+
expect(logStr()).toBe('');
2002+
syncResolve(deferred1, 'hi');
2003+
expect(logStr()).toBe('success(hi)->hi');
2004+
syncResolve(deferred2, 'cau');
2005+
expect(logStr()).toBe('success(hi)->hi');
2006+
syncReject(deferred, 'hola');
2007+
expect(logStr()).toBe('success(hi)->hi');
2008+
});
2009+
2010+
it('should reject as soon as the first promise is settled by rejection', function() {
2011+
var deferred1 = defer(),
2012+
deferred2 = defer();
2013+
2014+
q.race([promise, deferred1.promise, deferred2.promise]).then(success(), error());
2015+
expect(logStr()).toBe('');
2016+
syncReject(deferred1, 'hi');
2017+
expect(logStr()).toBe('error(hi)->reject(hi)');
2018+
syncResolve(deferred2, 'cau');
2019+
expect(logStr()).toBe('error(hi)->reject(hi)');
2020+
syncReject(deferred, 'hola');
2021+
expect(logStr()).toBe('error(hi)->reject(hi)');
2022+
});
2023+
});
2024+
2025+
describe('race (hash)', function() {
2026+
it('should do nothing if given an empty array', function() {
2027+
q.race({}).then(success(), error());
2028+
expect(mockNextTick.queue.length).toBe(0);
2029+
expect(logStr()).toBe('');
2030+
});
2031+
2032+
it('should resolve as soon as the first promise is settled by resolution', function() {
2033+
var deferred1 = defer(),
2034+
deferred2 = defer();
2035+
2036+
q.race({a: promise, b: deferred1.promise, c: deferred2.promise}).then(success(), error());
2037+
expect(logStr()).toBe('');
2038+
syncResolve(deferred1, 'hi');
2039+
expect(logStr()).toBe('success(hi)->hi');
2040+
syncResolve(deferred2, 'cau');
2041+
expect(logStr()).toBe('success(hi)->hi');
2042+
syncReject(deferred, 'hola');
2043+
expect(logStr()).toBe('success(hi)->hi');
2044+
});
2045+
2046+
it('should reject as soon as the first promise is settled by rejection', function() {
2047+
var deferred1 = defer(),
2048+
deferred2 = defer();
2049+
2050+
q.race({a: promise, b: deferred1.promise, c: deferred2.promise}).then(success(), error());
2051+
expect(logStr()).toBe('');
2052+
syncReject(deferred1, 'hi');
2053+
expect(logStr()).toBe('error(hi)->reject(hi)');
2054+
syncResolve(deferred2, 'cau');
2055+
expect(logStr()).toBe('error(hi)->reject(hi)');
2056+
syncReject(deferred, 'hola');
2057+
expect(logStr()).toBe('error(hi)->reject(hi)');
2058+
});
2059+
});
2060+
19892061
describe('exception logging', function() {
19902062
var mockExceptionLogger = {
19912063
log: [],

0 commit comments

Comments
 (0)