]>
Commit | Line | Data |
---|---|---|
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 |