Select: Make compose-friendly by taking a known number of arguments.

This commit is contained in:
David Braun 2017-10-17 09:54:34 -04:00
parent d7355e17e1
commit 6ea2b8bafe
5 changed files with 24 additions and 22 deletions

View file

@ -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;

View file

@ -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 => {

View file

@ -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();

View file

@ -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();

View file

@ -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.`));
});
});