A tiny (~315B) utility that executes a dependency graph of async functions as concurrently as possible.
- Lightweight: ~315 bytes gzipped
- Unobtrusive and Unopinionated: takes normal functions; returns a normal function!
- Isomorphic: works in node and the browser
- Easy Debugging: provides type-level validation of the input graph, including cycle detection!
- Awesome Logo: designed by Jill Marbach!
$ npm i grfn
import { setTimeout } from 'node:timers/promises'
import grfn from 'grfn'
const fn = grfn({
// `e` depends on `a`, `c`, and `d`. Call `e` with the results of the
// functions once their returned promises resolve.
e: [
async (a, c, d) => {
await setTimeout(10)
return a * c * d
},
[`a`, `c`, `d`],
],
// `d` depends on `b`.
d: [
async b => {
await setTimeout(1)
return b * 2
},
[`b`],
],
// `c` depends on `a` and `b`.
c: [
async (a, b) => {
await setTimeout(5)
return a + b
},
[`a`, `b`],
],
// `a` and `b` have no dependencies! But they must still be listed. They take
// the input given to `fn`.
a: async (n1, n2, n3) => {
await setTimeout(15)
return n1 + n2 + n3
},
b: async (n1, n2, n3) => {
await setTimeout(10)
return n1 * n2 * n3
},
})
const output = await fn(4, 2, 3)
// This will be the output of `e` because no function depends on it!
console.log(`final output: ${output}`)
Output:
final output: 14256
The graph will be automatically validated, including cycle detection, via TypeScript magic!
Returns a function that runs the dependency graph of functions described by
vertices
:
- Input: passed to the functions that don't have dependencies in the graph.
- Output: a
Promise
that resolves to the value returned from the graph's output function, the function that is not depended on by any function.
Type: { [key: string]: Function | [Function, string[]?] }
An object describing a dependency graph of functions.
Each value in vertices
must be either:
- A pair containing a function and its array of dependencies by key (e.g.
[fnA, ['keyB', 'keyC']]
) - Or a function (equivalent to
[fn, []]
)
The following constraints, which are validated via TypeScript magic, must also be met:
- Each dependency in
vertices
must also appear as a non-dependency:- Not okay (
b
doesn't appear as a non-dependency):grfn({ a: [fnA, [`b`]], })
- Okay:
grfn({ a: [fnA, [`b`]], b: fnB, })
- Not okay (
-
vertices
must describe an acyclic dependency graph:- Not okay (cycle:
a -> b -> a
):grfn({ a: [fnA, [`b`]], b: [fnB, [`a`]], })
- Okay:
grfn({ a: [fnA, [`b`]], b: fnB, })
- Not okay (cycle:
-
vertices
must have exactly one output function, a function that is not depended on by any function:- Not okay (both
b
andc
are not depended on by any function):grfn({ b: [fnB, [`a`]], c: [fnC, [`a`]], a: fnA, })
- Okay:
grfn({ d: [fnD, [`b`, `c`]], b: [fnB, [`a`]], c: [fnC, [`a`]], a: fnA, })
- Not okay (both
Stars are always welcome!
For bugs and feature requests, please create an issue.