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