Skip to content

Links

Module Iterables.Chains

Links are the things you use when calling Chains.run() or Chains.prepare() . These are the little functions which work with data flowing through the chain, and pass it on to the next link.

Typically several links are used to make a chain. If you’ve only got one link, perhaps there is a simpler way to do it.

Here’s an overview of the in-built links

Math functions

  • min, max, average, sum, tally

Filtering

  • filter, drop
  • rank, rankArray

Changing the shape of values

  • chunk
  • reduce

Timing of values

  • debounce, delay

Stopping a chain

  • duration
  • take

Math

min / max

For every input value, min and max will always emit the smallest or largest value seen so far.

const ch = Chains.run(
Chains.From.array([1,2,3,4]),
Chains.Links.min();
)
// Produces 1, 1, 1, 1

Works with chains that output numbers or array of numbers. Non-numbers are skipped.

average()

Taking a numeric input (or array of numbers), average continuously returns a running average.

Chains.Links.average();

Non-numbers in the input stream are skipped.

sum()

Taking a numeric input (or array of numbers), sum returns the current total.

Non-numbers in the input stream are skipped.

tally

tally throws away the input value and instead emits the total number of values produced.

Example usage:

const ch = Chains.run(
Chains.From.timestamp({ interval: 100 }),
Chains.Links.tally()
);
for await (const v of ch) {
// Produces: 1, 2, 3 ... every 100ms
}

Filtering

filter

filter only passes values for which the predicate function returns true.

// Only allow even numbers to pass,
// dropping all odd numbers
Chain.Links.filter(v => v % 2 === 0)

drop

drop is the opposite of filter. Instead dropping values which the predicate function returns true

// Drop all even numbers,
// only allowing odd numbers to pass
Chain.Links.drop(v => v % 2 === 0)

rank / rankArray

rank allows values to be scored using some function, emitting the ‘best’ value. rankArray is the same, but it works within a set of values.

The ranking function gets two parameters, a and b, and is expected to return a string value denoting which is the best, or ‘eq’ if they are equal.

Eg, ranking objects based off a ‘size’ field:

Chains.Links.rank((a,b) => {
if (a.size > b.size) return `a`;
if (a.size < b.size) return `b`;
return `eq`
})

rank has some options about when to emit a value downstream. By default, it won’t emit a new value if it’s equally ranked. And by default it won’t emit a value until it ‘beats’ the last value.

You can change these, for example:

Chains.Links.rank(fn, {
emitEqualRanked: true,
emitRepeatHighest: true
});

rankArray works instead with arrays as input values. By default, it behaves similarly to rank, but checks the contents of the array. If the withinArrays option is set to true, it will instead emit the highest value within each array, and not care about previous values.

Changing shape

transform

transform Takes an input value and returns an output value.

// Eg. return a doubled version of the input value
Chains.Links.transform( v => v * 2 );

Example usage

const ch = Chains.run(Chains.From.array([1,2,3,4]),
Chains.Links.transform( v => v * 2)
);
for await (const v of ch) {
// 2, 4, 6, 8
}

reduce

reduce assumes its input is an array, returning a single combined result using a function.

// Return the largest of the values
Chains.reduce(values => Math.max(...values));

Example usage

// Create a chain that flattens values
const reduce = Chains.reduce(values => Math.max(...values));
// Feed it a single input (an array), get a single output back:
const result = await Chains.single(reduce, [ 1, 2, 3]); // 3

chunk

Given a stream of values, chunk breaks it up into arrays of a given length.

For example, given a chunk size of 3:

Chains.Links.chunk(3);

If the stream of input values is: 1, 2, 3, 4, 5, 6 we would get chunks of [ 1, 2, 3], [ 4, 5, 6 ]

By default, if the stream ends and a chunk is not complete, it is returned regardless. Set the second parameter to chunk to false (ie Chains.Link.chunk(3, false)) to instead throw away the under-sized chunk.

Timing

delay

delay changes the timing of the stream, allowing you to add delay before or after a value is yielded.

Chains.Links.delay({ before:1000 });
Chains.Links.delay({ after:1000 });

Example usage

const ch = Chains.run(Chains.From.event(document, `click`),
Chains.Links.delay({ before: 1000 });
);
for await (const v of ch) {
// Runs 1s after a click
}

debounce

debounce ensures a minimum time between values. Values produced too quickly are dropped.

Chain.Links.debounce(100); // 100ms

Example usage:

const chain = Chains.run(
// Produce values every 10ms for 350ms
Chains.From.timestamp({ interval: 10, elapsed: 350 }),
// Only let a value through every 100ms
Chains.Links.debounce(100)
);

Stopping a chain

take

take will return the input value, but will break the chain after a certain number of values flow through it.

// Stop after 5 results
Chains.Links.take(5);

Example usage:

// Handle five click events and then finish
const ch = Chains.run(Chains.From.event(document, `click`),
Chains.Links.take(5)
)

duration

duration will close a chain after a given interval has elapsed.

Chains.Links.duration(100); // 100ms