Skip to content

Commit 22f5925

Browse files
author
Tim Blasi
committed
fix(facade): Make PromiseWrapper#all semantics equivalent
The semantics between ES6 `Promise#all` and Dart's `Future#wait` are different for values that are not `Promise`/`Future`s. In ES6, non-`Promise` values are immediately completed to their current value. In Dart, non-`Future` values cause an error. Updated Dart's `PromiseWrapper#all` implementation to conform to the ES6 spec.
1 parent cd52d8a commit 22f5925

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

modules/angular2/src/facade/async.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ class PromiseWrapper {
99
static Future reject(obj, stackTrace) => new Future.error(obj,
1010
stackTrace != null ? stackTrace : obj is Error ? obj.stackTrace : null);
1111

12-
static Future<List> all(List<Future> promises) => Future.wait(promises);
12+
static Future<List> all(List<dynamic> promises) {
13+
return Future
14+
.wait(promises.map((p) => p is Future ? p : new Future.value(p)));
15+
}
1316

14-
static Future then(Future promise, success(value), Function onError) {
17+
static Future then(Future promise, success(value), [Function onError]) {
1518
if (success == null) return promise.catchError(onError);
1619
return promise.then(success, onError: onError);
1720
}

modules/angular2/src/facade/async.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ export class PromiseWrapper {
1818
return promise.catch(onError);
1919
}
2020

21-
static all(promises: List<Promise<any>>): Promise<any> {
21+
static all(promises: List<any>): Promise<any> {
2222
if (promises.length == 0) return Promise.resolve([]);
2323
return Promise.all(promises);
2424
}
2525

2626
static then<T>(promise: Promise<T>, success: (value: any) => T | Thenable<T>,
27-
rejection: (error: any, stack?: any) => T | Thenable<T>): Promise<T> {
27+
rejection?: (error: any, stack?: any) => T | Thenable<T>): Promise<T> {
2828
return promise.then(success, rejection);
2929
}
3030

modules/angular2/test/facade/async_spec.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from 'angular2/test_lib';
1515

1616
import {ObservableWrapper, EventEmitter, PromiseWrapper} from 'angular2/src/facade/async';
17+
import {ListWrapper} from 'angular2/src/facade/collection';
1718

1819
export function main() {
1920
describe('EventEmitter', () => {
@@ -62,4 +63,45 @@ export function main() {
6263
// should call dispose on the subscription on throw
6364
// should call dispose on the subscription on return
6465
});
65-
}
66+
67+
// See ECMAScript 6 Spec 25.4.4.1
68+
describe("PromiseWrapper", () => {
69+
describe("#all", () => {
70+
it("should combine lists of Promises", inject([AsyncTestCompleter], (async) => {
71+
var one = PromiseWrapper.completer();
72+
var two = PromiseWrapper.completer();
73+
74+
var all = PromiseWrapper.all([one.promise, two.promise]);
75+
var allCalled = false;
76+
77+
PromiseWrapper.then(one.promise, (_) => {
78+
expect(allCalled).toBe(false);
79+
two.resolve('two');
80+
});
81+
82+
PromiseWrapper.then(all, (_) => {
83+
allCalled = true;
84+
async.done();
85+
});
86+
87+
one.resolve('one');
88+
}));
89+
90+
ListWrapper.forEach([null, true, false, 10, 'thing', {}, []], (abruptCompletion) => {
91+
it(`should treat "${abruptCompletion}" as an "abrupt completion"`,
92+
inject([AsyncTestCompleter], (async) => {
93+
var one = PromiseWrapper.completer();
94+
95+
var all = PromiseWrapper.all([one.promise, abruptCompletion]);
96+
97+
PromiseWrapper.then(all, (val) => {
98+
expect(val[1]).toEqual(abruptCompletion);
99+
async.done();
100+
});
101+
102+
one.resolve('one');
103+
}));
104+
});
105+
});
106+
});
107+
}

0 commit comments

Comments
 (0)