flow-sequencer
Breaking News
I'm currently working on FEATURES.md.
This file will contain a, feature by feature description of how it works (with all of the tricks you can't see, unless you look at the code). It's still a work in progress and it starts off with the new Template Feature.
Basic Concept
While working with SailsJS I ran into the one of the pains of NodeJS programming: Nested Callbacks. It's also one of the advantages of Node. Unfortunately, it makes for very ugly code.
The natural solution would be to use a module like 'async' to solve the problem. But, I prefer to re-invent the wheel (Actually, I don't, I just needed something that made my code easier to read, more granular/reusable).
So, I created this module, to create a BASIC like structure to callbacks.
It's probably easier just to show a piece of code than explain how it works:
...// Create and Execute Call SequenceSequence start request: req response: res user: user ;...
This Basically creates an asynchronous call sequence, with some control structures (if/then/else, loop, goto, Nested Sequences, etc) sprinkled in. If you can live within this structure, it should make your code easier to read.
Basic API
.getInstance() - A wrapper around new. Returns an instance of Sequence that you can then use.
.onSuccess(cb) - Method to call, if the Sequence Completes without Error.
.onError(cb) - Method to call, if an Error Occurs, while processing the Sequence.
.start(context) - Start the Sequence and pass in an optional Context Object.
Important
- 'context' has to be a javascript object.
- If you don't pass in a 'context' object, an empty object '{}' will be used as the context.
- The 'context' object will serve as the 'this' for all the methods (callbacks) used within the Sequence.
Within a method (callback) used in the Sequence the 'this' will always point to the 'context' object, WHICH, has been augmented with a series of functions to manage the Sequence's flow.
'context' methods
context.next() - Pass Control to the 'next' element in the sequence (method, if/then/else, loop, etc)
context.break() - Break out of a sequence or loop (in a parent sequence, it's more or less equivalent to .end())
context.end() - End the Sequence (break out of any loops nested and sequences)
context.errors() - register's errors in the sequence, and depending on the error settings, will break out of sequence or loop.
Examples
Sequence Control structure
......
Calls the method 'gt', with parameters qty and 1, which tests if the value of qty is greater than one, more or less equivalent to the following javascript code:
...;...
or in the context of the Sequence:
..._gt;...
The actual method:
.../** * Value is Greater than one? * * @param * @param * @returns */ { return compare > value ? this : this;}...
Important
- 'this' === 'context' passed in .start(...)
- this.true() and this.false() is how the 'gt' method communicates if the test passed or failed.
- if the test passed - the 'then' clause is 'executed'.
- if the test passed - the 'else' clause is 'executed'.
The method called by the 'else' clause (as named above)
... { // Save Sequence Context var context = this; // Create a New Sequence to Handle Package Creation var child = Sequence; // Save Parent Sequence and Set New Sequence Base var parent = context; // Execute Sequence child // Finish the Sequence startcontext;}...
This 'else' clause just basically creates a child sequence and executes it.
Normal Callback Method
... { // Save Sequence Context var context = this; // Find Stock Point by Code ERPObject ;}...
Notice that:
- on success, context.next() is called.
- on error, context.errors() is called.
- we save the value of 'point' as member of 'context' so that it can be used in other callbacks.