Synchronize asynchronous functions.
Usage
You need to pass two parameters to jfSync
:
- Functions list. This list can be specified using two formats:
- Functions: each item is a function.
- Object: each item is an object with keys:
- fn : Function to execute (mandatory).
- args : Arguments to pass to function (default:
[]
). - scope: Scope of function execution (default:
fn
).
- Callback: Callback to execute at end of run. The signature is
(error, data)
.
As NodeJS callbacks, each function will receive a callback function as last parameter. The function will be responsible of calling this callback when finish.
The functions list WILL BE modified and each item WILL BE replaced with result of
function execution received in data
parameter of callback.
Examples
No errors.
Next, an example using 2 functions and 1 method. We will simulate asynchronous execution using a timer.
const jfSync = ; { ;}{ ;} ; const c = ; ;
As you can see, we can execute methods in class instances using scope
key.
With errors.
When an error occurs and error
is an instance of Error
you can check in
error.index
the index of failed function.
You can retrieve results of previous functions in data
parameters
iterating from index 0
to error.index
or using data.slice(0, error.index)
.
Remember, error
MUST BE an instance of Error
if you want to retrieve previous
values using error.index
.
const jfSync = ; { ;}{ ;}{ ;} ;
Nested jfSync
Next, a more complicated example: a decorator system.
Each decorator will modify an object using two methods:
before
: Executed before calling object method.after
: Executed after calling object method.
Each decoration process can be asynchronous, so values added to decorated object
can be read from DB, web, etc., and call cb(error, data)
in right moment.
const jfSync = ;//------------------------------------------------------------------------------// Decorator classes.//------------------------------------------------------------------------------ // This method must be abstract and implemented in child class const _name = thisconstructorname; objafter; ; // This method must be abstract and implemented in child class const _name = thisconstructorname; objbefore; ; {} {}//------------------------------------------------------------------------------// Class to decorate.//------------------------------------------------------------------------------ { thisafter = ; thisbefore = ; } ; //------------------------------------------------------------------------------// Add a new decorator to list.//------------------------------------------------------------------------------{ const _decorator = ; after; before;}//------------------------------------------------------------------------------// Decorate object.//------------------------------------------------------------------------------// Object to decorate.const decorated = ;// Functions to call after decoration.const after = ;// Functions to call before decoration.const before = ;// Add all decorators required.;;// Sync decoration process.;
Output after script execution:
ERROR: null
DATA : [
[
[ 'DecoratorOne', 'before' ],
[ 'DecoratorTwo', 'before' ]
],
[
'NeedDecoration: between after and before'
],
[
[ 'DecoratorOne', 'after' ],
[ 'DecoratorTwo', 'after' ]
]
]
OBJ : NeedDecoration {
after : [ 'DecoratorOne', 'DecoratorTwo' ],
before : [ 'DecoratorOne', 'DecoratorTwo' ]
}
As you can see, each decorator was executed in a synchronous way and modified object in expected order.
Remember, data
will have results of each method executed instead of
original functions.
You can use this example and change some parts for testing errors.