enque
Version:
Run asynchonous functions in succession while potentially operating on the same data.
220 lines (171 loc) • 6.01 kB
Markdown
# enQue.js
Chain asynchronous functions in succession, consuming the same data stream.
```javascript
const Que = new require('enQue');
Que([fn1, fn2, fn3, fn4, fn5]).run(data).then(data=>YOUR_CALLBACK(data));
// Where each fn follows the format fn(data, next) { /*example: */ data.size++; next() }
// data must be an OBJECT! ie: myQue.run({text:"Hi"}) then in your callback its data.text
```
For full documentation see the [enQue full docs](https://ileathan.github.io/enQue).
# Features
**1.)** Skip ahead in the que `next(4)` would skip to position 4.
**2.)** Go backwards in the que `next(-4)` would go back 4.
**3.)** Inject a `Function` at a particular que index `next({inject:4,function:Function})`. __(runs parallel to que not sync'd)__
**4.)** Quit after a specified amount of que spots `next({quit:4})` quits after 4 more iterations.
**5.)** Allows removing functions from the que by index, variable name, or raw text.
**6.)** A fill method for convenience.
The above code snippet illustrates how simple it would be to execute 5 asynchronous functions in succession that all operate on the same data. When you add a function to the que **accept the second a parameter** (data is first) and **make sure to call it** for example `FUNCTION_NAME(data, next) { /* example: */ data.size + 1; /* MANDATORY */ next() }`. You can also use `next(0)` to quit early. The entire point of this package is that each spot in the que wont run untill the last spot has said ok im done via calling `next()`, or whatever you chose to name it.
Since a promise is returned it is always best to attach a `.then()` and `.catch()` so the above code would become.
```javascript
myQue.run(data)
.then(sucessCallback); // Passed 1 argument, the data OBJECT.
.catch(errorCallback); // Passed 1 argument, the error.
```
# Instalation
```npm install enque```
# Dependencies
None.
# Usage examples
```javascript
// USAGE EXAMPLE
const Que = require('enQue');
const que = new Que();
// Used to only go backwards once, otherwise you end up in an infinite cycle.
// IF YOU GO FORWARD IN THE QUE YOU CANNOT GO BACKWARDS TO A PLACE NOT ON THE NEW QUE
// It will throw a error if you attempt to go forward then backwards.
var once = true;
que.add((data, next, done, index) => {
// index is the position of your function in the que, 0 right now.
//return done(); // You can return early if you'd like
setTimeout(()=>{
data.msg += ' ONE';
// You can inject a function at a specified relative position (it isnt added to the que, it runs parallel so careful here).
//next({inject:7, function: function(data) {data.msg += " ONE AND A HALF";}}); // This would run that function after 7 more que'd fn's are done.
next()
}, 9000)
});
que.add((data, next) => {
setTimeout(()=>{
//throw "errors work too" // You can throw an error and reject the promise
data.msg += ' TWO';
next();
}, 4000)
});
que.add((data, next) => {
data.msg += ' THREE';
next()
});
function myFn1(data, next) {
data.msg += ' FOUR';
// You can go backwards in the que.
if(once) { once = false; next(-2); }
// You can go forwards in the que.
else next(1);
}
function myFn2(data, next) {
data.msg += ' FIVE';
next();
}
// You can add multiple functions at a time.
que.add([myFn1, myFn2])
que.run({msg: 'ZERO'})
.then(res => console.log(res.msg))
.catch(err => console.log('Woopsie! ' + err))
```
Executing the above code as is gives:
```
ONE TWO THREE FOUR TWO THREE FOUR FIVE
```
# More examples
**NOTE** You can't actually call `que.run()` then `que.clear()` because the que may still be processing. You need to call. `que.run().then(()=>que.clear())` or to extract data from the processed que `que.run().then(data=>YOUR_CALLBACK(data))`. Each function in your que is handed data as a first parameter whether or not you originally passed one in. default `{}`
```javascript
// For the purpose of these examples, assume each function is asynchronous and you don't know when it will finish execution.
// When operating on the data it is important to remember that it must not be a primitive. If you must operate on just a primitive
// set it to an attribute on an object. for example if you need to operate on a `Number` you can do `que.run({data.number=17})`.
Que = require('enQue');
que = new Que();
function fn1(data, next) {
console.log(1);
next();
}
function fn2(data, next) {
console.log(2);
next();
}
que.add(fn1);
que.run(); // 1
que.clear();
que.add([fn1, fn1, fn1]);
que.run(); // 1 1 1
que.clear();
que.fill(fn1, 7);
que.run();
que.clear(); // 1 1 1 1 1 1 1
que.add([fn1, fn1, fn1]);
que.remove(fn1);
que.run(); // ""
que.add([fn1, fn2, fn2, fn2]);
que.remove([fn1, fn2], 3); // for best preformance only pass in numbers i.e. `remove(0); remove(1); remove(2)`
que.run(); // 2
que.clear();
que.add([(d,n)=>n(5), fn1, fn1, fn1, fn1, fn1, fn1]);
que.run(); // 1
que.clear();
que.add([(d,n)=>n({quit:3}), fn1, fn1, fn1, fn2, fn2, fn2]);
que.run(); // 1 1 1
que.clear();
que.add((d,n,i)=>{console.log("hi"); n()});
que.remove('(d,n,i)=>{console.log("hi"); n()}');
que.run(); // ""
fn5 = (data, next, index, done) => {
console.log(index);
index === 2 ? next(0) : next();
// instead of next(0) you can use done()
}
que.add([fn5, fn5, fn5, fn5, fn5]);
que.run(); // 0 1 2
que.clear();
fn3 = (data, next) => {
data.data = "SEVEN";
next();
}
que.add([(d,n)=>n({inject:5, function: function(d){d.data="7"}}), fn3, fn3, fn3, fn3, fn3]);
que.run().then(res=>console.log(res)); // d.data === 7
// To initialise the data use `run(data)` where data is an Object.
que.clear();
function fn6(data, next, index) {
throw new Error("Woopsie!");
next();
}
que.add([fn6, fn6, fn6, fn6, fn6]);
que.run().catch(e=>console.log(e)); // prints the thrown error.
```
Executing the above code as is gives:
```
1
1
1
1
1
1
1
1
1
1
1
2
1
1
1
1
0
1
2
{ data: '7' }
Error: Woopsie!
at fn6 (...)
at options (...)
at enQue.executeQue (...)
at ...
...
```