Skip to content

Commit

Permalink
feat: support ES2015 iterables in all() and race() (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
motiz88 authored Mar 2, 2020
1 parent 81b5722 commit e9c12a2
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/es6-extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,20 @@ Promise.resolve = function (value) {
return valuePromise(value);
};

var iterableToArray = function (iterable) {
if (typeof Array.from === 'function') {
// ES2015+, iterables exist
iterableToArray = Array.from;
return Array.from(iterable);
}

// ES5, only arrays and array-likes exist
iterableToArray = function (x) { return Array.prototype.slice.call(x); };
return Array.prototype.slice.call(iterable);
}

Promise.all = function (arr) {
var args = Array.prototype.slice.call(arr);
var args = iterableToArray(arr);

return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
Expand Down Expand Up @@ -94,7 +106,7 @@ Promise.reject = function (value) {

Promise.race = function (values) {
return new Promise(function (resolve, reject) {
values.forEach(function(value){
iterableToArray(values).forEach(function(value){
Promise.resolve(value).then(resolve, reject);
});
});
Expand Down
110 changes: 110 additions & 0 deletions test/extensions-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,116 @@ describe('extensions', function () {
});
});
})

describe('a Set', function () {
describe('that is empty', function () {
it('returns a promise for an empty array', function (done) {
var res = Promise.all(new Set([]))
assert(res instanceof Promise)
res.then(function (res) {
assert(Array.isArray(res))
assert(res.length === 0)
})
.nodeify(done)
})
})
describe('of objects', function () {
it('returns a promise for the array', function (done) {
var res = Promise.all(new Set([a, b, c]))
assert(res instanceof Promise)
res.then(function (res) {
assert(Array.isArray(res))
assert(res[0] === a)
assert(res[1] === b)
assert(res[2] === c)
})
.nodeify(done)
})
})
describe('of promises', function () {
it('returns a promise for an array containing the fulfilled values', function (done) {
var d = {}
var resolveD
var res = Promise.all(new Set([A, B, C, new Promise(function (resolve) { resolveD = resolve })]))
assert(res instanceof Promise)
res.then(function (res) {
assert(Array.isArray(res))
assert(res[0] === a)
assert(res[1] === b)
assert(res[2] === c)
assert(res[3] === d)
})
.nodeify(done)
resolveD(d)
})
})
describe('of mixed values', function () {
it('returns a promise for an array containing the fulfilled values', function (done) {
var res = Promise.all(new Set([A, b, C]))
assert(res instanceof Promise)
res.then(function (res) {
assert(Array.isArray(res))
assert(res[0] === a)
assert(res[1] === b)
assert(res[2] === c)
})
.nodeify(done)
})
})
describe('containing at least one rejected promise', function () {
it('rejects the resulting promise', function (done) {
var res = Promise.all(new Set([A, rejected, C]))
assert(res instanceof Promise)
res.then(function (res) {
throw new Error('Should be rejected')
},
function (err) {
assert(err === rejection)
})
.nodeify(done)
})
})
describe('containing at least one eventually rejected promise', function () {
it('rejects the resulting promise', function (done) {
var rejectB
var rejected = new Promise(function (resolve, reject) { rejectB = reject })
var res = Promise.all(new Set([A, rejected, C]))
assert(res instanceof Promise)
res.then(function (res) {
throw new Error('Should be rejected')
},
function (err) {
assert(err === rejection)
})
.nodeify(done)
rejectB(rejection)
})
})
describe('with a promise that resolves twice', function () {
it('still waits for all the other promises', function (done) {
var fakePromise = {then: function (onFulfilled) { onFulfilled(1); onFulfilled(2) }}
var eventuallyRejected = {then: function (_, onRejected) { this.onRejected = onRejected }}
var res = Promise.all(new Set([fakePromise, eventuallyRejected]))
assert(res instanceof Promise)
res.then(function (res) {
throw new Error('Should be rejected')
},
function (err) {
assert(err === rejection)
})
.nodeify(done)
eventuallyRejected.onRejected(rejection);
})
})
describe('when given a foreign promise', function () {
it('should provide the correct value of `this`', function (done) {
var p = {then: function (onFulfilled) { onFulfilled({self: this}); }};
Promise.all(new Set([p])).then(function (results) {
assert(p === results[0].self);
}).nodeify(done);
});
});
})
})

describe('promise.done(onFulfilled, onRejected)', function () {
Expand Down

0 comments on commit e9c12a2

Please sign in to comment.