From 3ff3031b1e57263d8a33b4edc81d229f0af409a1 Mon Sep 17 00:00:00 2001 From: David Braun Date: Wed, 20 Mar 2019 11:09:26 -0400 Subject: [PATCH] Simplify implementation of `select`. --- lib/index.js | 68 +++++++++++++++++++++++++-------------------------- test/index.js | 6 ++--- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/index.js b/lib/index.js index a5d88a5..ac6e97b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -403,45 +403,45 @@ Channel.of = (...values) => Channel.from(values); Channel.isChannel = arg => arg !== undefined && arg !== null && Object.getPrototypeOf(arg) === prototype; -Channel.select = methodPromises => - Object.assign( - new Promise((resolve, reject) => { +Channel.select = methodPromises => { + if (!Array.isArray(methodPromises)) { + throw new TypeError(`Channel.select: Argument must be an array.`); + } + + const selectPromise = new Promise((resolve, reject) => { + methodPromises.forEach(async promise => { try { - methodPromises.forEach(async promise => { - try { - promise.prethen(() => { - // We've been given a heads-up that this method will complete first - // so cancel the other method calls. - methodPromises.forEach(other => { - if (other !== promise) { - other.cancel(); - } - }); - }); - - try { - await promise; - } catch (exception) { - reject(exception); + promise.prethen(() => { + // We've been given a heads-up that this method will complete first + // so cancel the other method calls. + methodPromises.forEach(other => { + if (other !== promise) { + other.cancel(); } - - resolve(promise.channel); - } catch (exception) { - reject( - new TypeError( - `Channel.select accepts only promises returned by push & shift.` - ) - ); - } + }); }); + + try { + await promise; + } catch (exception) { + reject(exception); + } + + resolve(promise.channel); } catch (exception) { - reject(new TypeError(`Channel.select: Argument must be an array.`)); + reject( + new TypeError( + `Channel.select accepts only promises returned by push & shift.` + ) + ); } - }), - { - cancel: () => Promise.all(methodPromises.map(promise => promise.cancel())) - } - ); + }); + }); + + return Object.assign(selectPromise, { + cancel: () => methodPromises.forEach(promise => promise.cancel()) + }); +}; // functional interface allowing full or partial application // diff --git a/test/index.js b/test/index.js index 1902fc8..b46ee81 100644 --- a/test/index.js +++ b/test/index.js @@ -98,6 +98,7 @@ describe(`Channel function`, function() { it(`miscellaneous`, async function() { const a = Channel(); const b = Channel(); + (async () => { await b.push(0); await a.push(1); @@ -114,10 +115,9 @@ describe(`Channel function`, function() { it(`allows for non-blocking selects`, async function() { const a = Channel(); const b = Channel(); + const closed = Channel.of(); - switch ( - await Channel.select([a.shift(), b.push(0), Channel.of().shift()]) - ) { + switch (await Channel.select([a.shift(), b.push(0), closed.shift()])) { case a: assert(false); break;