-
Notifications
You must be signed in to change notification settings - Fork 0
/
example.mjs
130 lines (122 loc) · 3.39 KB
/
example.mjs
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
import { buildRocket, fetchCrew, getFuel, bookLaunchPad } from './index.mjs';
//
// Ejecuta funciones asíncronas basadas en callbacks de forma concurrente.
//
// Espera que el 1er argumento (`obj`) sea un objeto donde cada propiedad
// contiene una función que recibe un callback como único argumento.
//
// Una vez se hayan completado todas las tareas, se invocará `cb` con un objeto
// como 2ndo argumento, y este objeto tendrá las mismas propiedades que el
// objeto que recibimos como input (`obj`) y los valores corresponden al
// _resultado_ de cada una de las funciones asíncronas.
//
const concurrent = (obj, cb) => {
let hasErrored = false;
const results = {};
const keys = Object.keys(obj);
const handler = name => (err, data) => {
if (hasErrored) {
return;
}
if (err) {
hasErrored = true;
return cb(err);
}
Object.assign(results, { [name]: data });
if (Object.keys(results).length === keys.length) {
cb(null, results);
}
};
keys.forEach((key) => {
obj[key](handler(key));
});
};
//
// Ejecuta funciones asíncronas basadas en callbacks en series (de forma
// secuencial).
//
// Espera un arreglo de funciones como primer argumento. Estas funciones reciben
// un callback como único argumento.
//
// Una vez se hayan completado todas las tareas, se invocará `cb` con un arreglo
// como 2ndo argumento, y este arreglo tendrá el mismo número de elementos que
// el arreglo que recibimos como input (`fns`), y los valores corresponden al
// _resultado_ de cada una de las funciones asíncronas.
//
const series = (fns, cb) => {
const recurse = (remaining, memo = []) => {
if (!remaining.length) {
return cb(null, memo);
}
remaining[0]((err, data) => {
if (err) {
return cb(err);
}
return recurse(remaining.slice(1), memo.concat(data));
});
};
return recurse(fns);
};
const initMission = cb => concurrent({
rocket: buildRocket,
crew: fetchCrew,
fuel: getFuel,
launchPad: bookLaunchPad,
}, cb);
const getReadyForLaunch = ({ rocket, crew, fuel, launchPad }, cb) => {
series([
launchPad.addRocket.bind(null, rocket),
rocket.addCrew.bind(null, crew),
rocket.addFuel.bind(null, fuel),
], cb);
};
const launch = ({ rocket, crew, fuel, launchPad }, cb) => {
const fire = (err) => {
if (err) {
return cb(err);
}
if (rocket.altitude < 100) {
return rocket.fireEngine(0, fire);
}
if (rocket.altitude < 400 && rocket.engineIsFiring(0)) {
return series([
rocket.stopEngine.bind(null, 0),
rocket.runStageSeparation.bind(null, 0),
], fire);
}
if (rocket.altitude < 400) {
return rocket.fireEngine(1, fire);
}
return series([
rocket.stopEngine.bind(null, 1),
rocket.runStageSeparation.bind(null, 1),
], cb);
};
fire();
};
export const run = (cb) => {
const start = Date.now();
return initMission((err, mission) => {
if (err) {
return cb(err);
}
return series([
getReadyForLaunch.bind(null, mission),
launch.bind(null, mission),
], (err) => {
if (err) {
return cb(err);
}
console.log(`Total time: ${Math.floor((Date.now() - start) / 1000)} secs`);
cb();
});
});
};
if (typeof process !== 'undefined' && process.env.NODE_ENV !== 'test') {
run((err) => {
if (err) {
console.error(err);
process.exit(1);
}
});
}