Select: Make compose-friendly by taking a known number of arguments.
This commit is contained in:
parent
d7355e17e1
commit
6ea2b8bafe
5 changed files with 24 additions and 22 deletions
23
doc/API.md
23
doc/API.md
|
@ -4,7 +4,7 @@
|
||||||
- [close() -> async](#close---async)
|
- [close() -> async](#close---async)
|
||||||
- [readOnly() -> Channel](#readonly---channel)
|
- [readOnly() -> Channel](#readonly---channel)
|
||||||
- [writeOnly() -> Channel](#writeonly---channel)
|
- [writeOnly() -> Channel](#writeonly---channel)
|
||||||
- [Channel.select(methods) -> async channel](#channelselectmethods---async-channel)
|
- [Channel.select(promises) -> async channel](#channelselectpromises---async-channel)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
- [value](#value)
|
- [value](#value)
|
||||||
- [Array-like Properties](#array-like-properties)
|
- [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.
|
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
|
Wait for the first channel method promise to succeed and then cancel the rest.
|
||||||
the first one that succeeds. Only the winning method is executed to
|
Return the channel of the winning promise.
|
||||||
completion—the other methods have no effect.
|
|
||||||
|
|
||||||
All of the methods can be cancelled before completion by calling `cancel` on the
|
All of the promises can be cancelled before completion by calling `cancel` on
|
||||||
promise returned from `select`.
|
the promise returned by `select`.
|
||||||
|
|
||||||
### Examples
|
### 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.
|
into first: Alice, Bob, or Charlie.
|
||||||
|
|
||||||
```JavaScript
|
```JavaScript
|
||||||
switch (await Channel.select(
|
switch (await Channel.select([
|
||||||
alice.shift(),
|
alice.shift(),
|
||||||
bob.shift(),
|
bob.shift(),
|
||||||
charlie.push(`Hi!`)
|
charlie.push(`Hi!`)
|
||||||
)) {
|
])) {
|
||||||
case alice:
|
case alice:
|
||||||
console.log(`Alice said ${alice.value}.`);
|
console.log(`Alice said ${alice.value}.`);
|
||||||
break;
|
break;
|
||||||
|
@ -92,7 +91,7 @@ const increment = () => {
|
||||||
return counter;
|
return counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
await Channel.select(alice.push(increment()), bob.push(increment()));
|
await Channel.select([alice.push(increment()), bob.push(increment())]);
|
||||||
assert.equal(counter, 2);
|
assert.equal(counter, 2);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ channel to return immediately even if no other channels are ready:
|
||||||
const closed = Channel();
|
const closed = Channel();
|
||||||
closed.close();
|
closed.close();
|
||||||
|
|
||||||
switch (await Channel.select(alice.shift(), bob.shift(), closed.shift())) {
|
switch (await Channel.select([alice.shift(), bob.shift(), closed.shift())]) {
|
||||||
case alice:
|
case alice:
|
||||||
console.log(`Alice said ${alice.value}.`);
|
console.log(`Alice said ${alice.value}.`);
|
||||||
break;
|
break;
|
||||||
|
@ -123,7 +122,7 @@ You can also arrange it so that the `select` completes within a timeout:
|
||||||
const timeout = Channel();
|
const timeout = Channel();
|
||||||
setTimeout(timeout.close, 1000);
|
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:
|
case alice:
|
||||||
console.log(`Alice said ${alice.value}.`);
|
console.log(`Alice said ${alice.value}.`);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -300,7 +300,7 @@ Channel.of = (...values) => Channel.from(values);
|
||||||
|
|
||||||
Channel.isChannel = arg => prototype.isPrototypeOf(arg);
|
Channel.isChannel = arg => prototype.isPrototypeOf(arg);
|
||||||
|
|
||||||
Channel.select = (...methodPromises) =>
|
Channel.select = methodPromises =>
|
||||||
Object.assign(
|
Object.assign(
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
methodPromises.forEach(async promise => {
|
methodPromises.forEach(async promise => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ it(`doubleselect`, async function() {
|
||||||
// different channels.
|
// different channels.
|
||||||
const sender = async (n, c1, c2, c3, c4) => {
|
const sender = async (n, c1, c2, c3, c4) => {
|
||||||
for (let i = 0; i < n; i++) {
|
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();
|
c1.close();
|
||||||
|
|
|
@ -24,11 +24,11 @@ it(`select`, async function() {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
switch (await Channel.select(
|
switch (await Channel.select([
|
||||||
a.push(GetValue()),
|
a.push(GetValue()),
|
||||||
b.push(GetValue()),
|
b.push(GetValue()),
|
||||||
closed.shift()
|
closed.shift()
|
||||||
)) {
|
])) {
|
||||||
case a:
|
case a:
|
||||||
i++;
|
i++;
|
||||||
a = Channel();
|
a = Channel();
|
||||||
|
|
|
@ -89,10 +89,10 @@ describe(`Channel`, function() {
|
||||||
await a.shift();
|
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(b.value, 0);
|
||||||
assert.equal(await a.shift(), 1);
|
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();
|
const nonBlocking = Channel();
|
||||||
nonBlocking.close();
|
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:
|
case a:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
@ -119,9 +119,12 @@ describe(`Channel`, function() {
|
||||||
|
|
||||||
it(`cancel`, async function() {
|
it(`cancel`, async function() {
|
||||||
const channel = Channel();
|
const channel = Channel();
|
||||||
Channel.select(channel.push(`cancelled`)).cancel();
|
Channel.select([channel.push(`cancelled`)]).cancel();
|
||||||
const closed = Channel.of();
|
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();
|
const channel = Channel();
|
||||||
|
|
||||||
return assertRejects(async () => {
|
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.`));
|
}, new TypeError(`Can't push 'undefined' to channel, use close instead.`));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue