diff --git a/doc/API.md b/doc/API.md index 0fe9e86..cb55a2e 100644 --- a/doc/API.md +++ b/doc/API.md @@ -4,7 +4,7 @@ - [close() -> async](#close---async) - [readOnly() -> Channel](#readonly---channel) - [writeOnly() -> Channel](#writeonly---channel) - - [Channel.select(methods) -> async channel](#channelselectmethods---async-channel) + - [Channel.select(promises) -> async channel](#channelselectpromises---async-channel) - [Examples](#examples) - [value](#value) - [Array-like Properties](#array-like-properties) @@ -47,14 +47,13 @@ Return a version of the channel that provides only read methods. Return a version of the channel that provides only write methods. -## Channel.select(methods) -> async channel +## Channel.select(promises) -> async channel -Attempt to call multiple channel `methods` in parallel and return the channel of -the first one that succeeds. Only the winning method is executed to -completion—the other methods have no effect. +Wait for the first channel method promise to succeed and then cancel the rest. +Return the channel of the winning promise. -All of the methods can be cancelled before completion by calling `cancel` on the -promise returned from `select`. +All of the promises can be cancelled before completion by calling `cancel` on +the promise returned by `select`. ### Examples @@ -62,11 +61,11 @@ Imagine you're at a party and your next conversation depends on whom you run into first: Alice, Bob, or Charlie. ```JavaScript -switch (await Channel.select( +switch (await Channel.select([ alice.shift(), bob.shift(), charlie.push(`Hi!`) -)) { +])) { case alice: console.log(`Alice said ${alice.value}.`); break; @@ -92,7 +91,7 @@ const increment = () => { return counter; }; -await Channel.select(alice.push(increment()), bob.push(increment())); +await Channel.select([alice.push(increment()), bob.push(increment())]); assert.equal(counter, 2); ``` @@ -103,7 +102,7 @@ channel to return immediately even if no other channels are ready: const closed = Channel(); closed.close(); -switch (await Channel.select(alice.shift(), bob.shift(), closed.shift())) { +switch (await Channel.select([alice.shift(), bob.shift(), closed.shift())]) { case alice: console.log(`Alice said ${alice.value}.`); break; @@ -123,7 +122,7 @@ You can also arrange it so that the `select` completes within a timeout: const timeout = Channel(); setTimeout(timeout.close, 1000); -switch (await Channel.select(alice.shift(), bob.shift(), timeout.shift())) { +switch (await Channel.select([alice.shift(), bob.shift(), timeout.shift())]) { case alice: console.log(`Alice said ${alice.value}.`); break; diff --git a/lib/index.js b/lib/index.js index 4525085..04d0792 100644 --- a/lib/index.js +++ b/lib/index.js @@ -300,7 +300,7 @@ Channel.of = (...values) => Channel.from(values); Channel.isChannel = arg => prototype.isPrototypeOf(arg); -Channel.select = (...methodPromises) => +Channel.select = methodPromises => Object.assign( new Promise((resolve, reject) => { methodPromises.forEach(async promise => { diff --git a/test/go/doubleselect.js b/test/go/doubleselect.js index 7f2ce13..c6e7c88 100644 --- a/test/go/doubleselect.js +++ b/test/go/doubleselect.js @@ -18,7 +18,7 @@ it(`doubleselect`, async function() { // different channels. const sender = async (n, c1, c2, c3, c4) => { for (let i = 0; i < n; i++) { - await Channel.select(c1.push(i), c2.push(i), c3.push(i), c4.push(i)); + await Channel.select([c1.push(i), c2.push(i), c3.push(i), c4.push(i)]); } c1.close(); diff --git a/test/go/select.js b/test/go/select.js index 1d9a9d5..2670ff3 100644 --- a/test/go/select.js +++ b/test/go/select.js @@ -24,11 +24,11 @@ it(`select`, async function() { let i = 0; do { - switch (await Channel.select( + switch (await Channel.select([ a.push(GetValue()), b.push(GetValue()), closed.shift() - )) { + ])) { case a: i++; a = Channel(); diff --git a/test/index.js b/test/index.js index 2afb25f..1ad12c6 100644 --- a/test/index.js +++ b/test/index.js @@ -89,10 +89,10 @@ describe(`Channel`, function() { await a.shift(); })(); - assert.equal(await Channel.select(a.shift(), b.shift()), b); + assert.equal(await Channel.select([a.shift(), b.shift()]), b); assert.equal(b.value, 0); assert.equal(await a.shift(), 1); - assert.equal(await Channel.select(a.push(0), b.shift()), a); + assert.equal(await Channel.select([a.push(0), b.shift()]), a); }); }); @@ -102,7 +102,7 @@ describe(`Channel`, function() { const nonBlocking = Channel(); nonBlocking.close(); - switch (await Channel.select(a.shift(), b.push(0), nonBlocking.shift())) { + switch (await Channel.select([a.shift(), b.push(0), nonBlocking.shift()])) { case a: assert(false); break; @@ -119,9 +119,12 @@ describe(`Channel`, function() { it(`cancel`, async function() { const channel = Channel(); - Channel.select(channel.push(`cancelled`)).cancel(); + Channel.select([channel.push(`cancelled`)]).cancel(); const closed = Channel.of(); - assert.equal(await Channel.select(channel.shift(), closed.shift()), closed); + assert.equal( + await Channel.select([channel.shift(), closed.shift()]), + closed + ); }); }); @@ -251,7 +254,7 @@ describe(`Channel object`, function() { const channel = Channel(); return assertRejects(async () => { - await Channel.select(channel.push(undefined)); + await Channel.select([channel.push(undefined)]); }, new TypeError(`Can't push 'undefined' to channel, use close instead.`)); }); });