]> git.r.bdr.sh - rbdr/grafn/blob - README.md
Ignore tap-snapshots from quality checks
[rbdr/grafn] / README.md
1 # Grafn
2
3 Graph + Fn: Execute functions as a graph.
4
5 ## What it's for?
6
7 Grafn lets you execute sequences of async functions by defining them as
8 vertices in a graph.
9
10 This allows you to easily define and manipulate complex dependencies in
11 asynchronous code.
12
13 ## How can I use it?
14
15 In order to use it you must first create a graph.
16
17 ```javascript
18 const Grafn = require('grafn');
19
20 const graph = new Grafn();
21 ```
22
23 Next you need to add some vertexes.
24
25 ```javascript
26 graph.vertex({
27 name: 'root',
28 action() {
29
30 return 5;
31 }
32 });
33 ```
34
35 This is a vertex without dependencies, it means it can be executed without
36 waiting for anything else. The return value of this function will be stored
37 so it can be used by its dependents.
38
39 You can add dependencies by listing the names as an array in the vertex definition.
40
41 ```javascript
42 graph.vertex({
43 name: 'addition',
44 dependencies: ['root'],
45 action(state) {
46
47 return state.root + state.root;
48 }
49 });
50 ```
51
52 Notice how the result of the `root` vertex is available in this action.
53
54 Vertexes will be executed as soon as all of their dependencies are met. For
55 example, consider the following graph
56
57 ```javascript
58 const Grafn = require('grafn');
59
60 const graph = new Grafn();
61
62 graph.vertex({
63 name: 'root',
64 action() {
65
66 return 5;
67 }
68 });
69
70 graph.vertex({
71 name: 'addition',
72 dependencies: ['root'],
73 action(state) {
74
75 return state.root + state.root;
76 }
77 });
78
79 graph.vertex({
80 name: 'subtraction',
81 dependencies: ['root'],
82 action(state) {
83
84 return state.root - state.root;
85 }
86 });
87
88 graph.vertex({
89 name: 'multiplication',
90 dependencies: ['root'],
91 action(state) {
92
93 return state.root * state.root;
94 }
95 });
96
97 graph.vertex({
98 name: 'division',
99 dependencies: ['root'],
100 action(state) {
101
102 return state.root / state.root;
103 }
104 });
105
106 graph.vertex({
107 name: 'tally',
108 dependencies: ['addition', 'subtraction', 'multiplication', 'division'],
109 action(state) {
110
111 console.log('+', state.addition);
112 console.log('-', state.subtraction);
113 console.log('*', state.multiplication);
114 console.log('/', state.division);
115 }
116 });
117 ```
118
119 The `addition`, `subtraction`, `multiplication`, and `division` vertices will
120 all run as soon as `roott` is executed. However, the final `tally` vertex won't
121 run until all other operations are complete.
122
123 You can visualize the graph by using the `graph.toString()` method. This
124 will output a graphviz digraph:
125
126 ```graphviz
127 digraph {
128 root
129 addition
130 root -> addition
131 subtraction
132 root -> subtraction
133 multiplication
134 root -> multiplication
135 division
136 root -> division
137 tally
138 addition -> tally
139 subtraction -> tally
140 multiplication -> tally
141 division -> tally
142 }
143 ```
144
145 ![execution graph, before execution][graph-pre-exec]
146
147 You can easily change the shape of the graph by changing the dependencies array.
148
149 In order to start execution of the graph you should select which node to start
150 from.
151
152 ```
153 graph.run('root');
154 ```
155
156 After an execution, you can use `graph.toString()` to check the result of an
157 execution. It will highlight which nodes were executed successfully (green), and
158 which nodes threw an error (red).
159
160 ![execution graph, after execution][graph-post-exec]
161
162 ## Acknowledgements
163
164 This project implements the same ideas behind [fluorine][fluorine], a similar
165 graph based library. Grafn wouldn't exist without it.
166
167 [fluorine]: https://github.com/freshout-dev/fluorine
168 [graph-pre-exec]: doc/images/graph-pre-exec.svg
169 [graph-post-exec]: doc/images/graph-post-exec.svg