Description
move-on
is a module that:
- executes the chosen functions (synchronous and | or asynchronous) in the chain [sample]
- can be a (really, really great) alternative for Promises
- supports timeout [sample] [sample]
- contains
four methods that immitate the Promises'
.all
and.race
methods [sample] [sample] [sample] - allows to set the
this
reference inner context for all functions in the chain to transmit data between functions [sample] [sample] [sample]
Any bugs found? Give me to know on GitHub.
Usage
Node
npm install move-on
const moveOn = ;
Browsers
Add the move-on.js
library to the HTML file.
The library is located in ./dist/move-on.js
directory.
It is a webpack&babel bundled cross-browser library version.
The library is accessible as moveOn
variable in the global (window) scope.
Tests
npm test
> git clone https://github.com/devrafalko/move-on.git> cd move-on> npm install> npm test //run tests in node> npm test err //run tests in node with failed specs shown> npm test deep //run tests in node with errors' descriptions shown
Simple sample
const moveOn = ; /* [Function] moveOn(list, config, onDone, onCatch) [Function] moveOn.all(list, config, onDone, onCatch) [Function] moveOn.each(list, config, onDone, onCatch) [Function] moveOn.first(list, config, onDone, onCatch) */ const list = retrieveData computeData displayData;const config = timeout: 5000 ; ; { ; //asynchronous resolve} { ; //synchronous resolve} { ;} {}{}
Methods short description
The module's methods expect the [Array]
list
of functions to be passed as the first argument. Each function in the chain has the
resolve
and
reject
parameter, that should be called when ready
(or failed) in order to move the functions execution forward. When the functions chain is successfully executed, the
done
callback function is called finally, otherwise the
catch
callback function is called.
1.
moveOn
The chained functions are executed sequentially
(one after another). Each function is expected to be
resolved
, so that the next chained function was executed. The
done
function is called as the last one, when all previous chained functions resolved. The
catch
function is called instead of
done
function, when at least one chained function failed
(rejected).
See the full description below.
See the samples: [sample] [sample] [sample] [sample] [sample] [sample] [sample]
2.
moveOn.all
The
all
static method of
move-on
module executes all chosen functions at the same time
(similarly to Promises'
.all
method). All chained functions are expected to be
resolved
so that the final
done
function was called. The
catch
function is called instead of
done
function, when at least one chained function failed
(rejected).
See the full description below.
See the samples: [sample]
3.
moveOn.each
The
each
static method of
move-on
module executes all chosen functions at the same time. Each chained function is expected to be either
resolved
or
rejected
, so that the final
done
function was called. The failed
(rejected) function
does not stop the further functions execution. It can be used
eg. to log the warnings in the
catch
callback function.
See the full description below.
See the samples: [sample]
4.
moveOn.first
The
first
static method of
move-on
module executes all chained functions at the same time. It expects the first
(fastest) function to be
resolved
, so that the
done
function was called
(similarly to Promises'
.race
method). When
all functions failed
(rejected), the
catch
function is called instead.
See the full description below.
See the samples: [sample]
Methods behaviour
moveOn(
list
,
config
,
done
,
catch
)
- The
move-on
module function executes thelist
functions sequentially (one after another) in the chain - When one
list
function resolves , the nextlist
function is called, and so on... - When the
last
list
function resolves , thedone
function is called once (it ends up the module execution) - When
whichever
list
function rejects , the fartherlist
functions and thedone
function are not called in the end - When
whichever
list
function rejects , thecatch
function is called instead once (it ends up the module execution) - Each
list
function can be resolved and | or rejected multiple times. The forks of chain are created and executed then [read more] - Each
list
function can execute the innermove-on
module [read more] - Samples: [sample] [sample] [sample] [sample] [sample] [sample] [sample]
moveOn.all(
list
,
config
,
done
,
catch
)
-
move-on
.all
static method executes all thelist
functions simultaneously (at the same time) - When one
list
function resolves , thedone
is not called immediately - The
done
waits, till alllist
functions are resolved , to be called (it ends up the module execution - after that, all resolve and reject calls are ignored) - When
whichever
list
function rejects , thedone
function is not called in the end - When
whichever
list
function rejects , thecatch
function is called instead once (it ends up the module execution - after that, all resolve and reject calls are ignored) - When
whichever
list
function resolves and | or rejects multiple times, only the first call is respected [read more] - Each
list
function can execute the innermove-on
module [read more] - Samples: [sample]
moveOn.each(
list
,
config
,
done
,
catch
)
-
move-on
.each
static method executes all thelist
functions simultaneously (at the same time) - When one
list
function resolves , thedone
is not called immediately - The
done
waits, till eachlist
function is either resolved or rejected , to be called (it ends up the module execution - after that, all resolve and reject calls are ignored) - When
whichever
list
function rejects and thecatch
is called, it does not end up the module execution - When
whichever
list
function resolves and | or rejects multiple times, only the first call is respected [read more] - Each
list
function can execute the innermove-on
module [read more] - Samples: [sample]
moveOn.first(
list
,
config
,
done
,
catch
)
-
move-on
.first
static method executes all thelist
functions simultaneously (at the same time) - The
done
waits, till the first (fastest)list
function is resolved , to be called (it ends up the module execution - after that, all resolve and reject calls are ignored) - When
all
list
functions reject , thedone
function is not called in the end - When
all
list
functions reject , thecatch
function is called instead once (it ends up the module execution - after that, all resolve and reject calls are ignored) - When
whichever
list
function resolves and | or rejects multiple times, only the first call is respected [read more] - Each
list
function can execute the innermove-on
module [read more] - Samples: [sample]
Arguments
list
[Array: function | array]
The [Array]
list
stores the list of functions, that should be called. It can contain:
- [Function] items
[see below] [sample] [sample] [sample] [sample]
const list = [fnA, fnB, fnC];
- or [Array] items that store the [Function] items
[see below]
const list = [fnA, [obj, fnB, fnC], fnD]
- or [Array] items that store the [String] names of methods
[see below] [sample]
const list = [fnA, [obj, 'fnB', 'fnC'], fnD]
1. [Function] items
- The [Array]
list
can contain [Function] items. It may be function, arrow function or object's method - All functions are
bound by default to the
config.context
reference (except arrow functions and already bound functions [read more]) - Samples: [sample] [sample] [sample] [sample]
const retrieveData = {};const computeData = {};const displayData = {} ;const list = retrieveData computeData displayDatadisplay;
2. [Array: function] items for individual binding
- All chained functions are
bound by default to the
config.context
reference - You can set the
individual
this
reference for the chosen functions (except arrow functions and already bound functions [read more]) - In order to bind the chained functions individually, push [Array] item into the
list
:- The
[0]
item should indicate the object or value to be thethis
reference for the functions - The
[1]
,[2]
, etc... item(s) should indicate the function(s), that will be bound to the[0]
object or value
- The
- The [Array] item's functions are bound to the given
[0]
object or value instead of theconfig.context
- The
config.bind
setting does not affect the individualthis
reference setting - The [Array] item's functions still have the access to the
config.context
parameter - the
list
can still contain the [Function] items next to this [Array] item
const workers = {} earnings = {} tasks = {};const config = context: tasks; //the default this referenceconst list = functionA //this === tasks workers functionB //this === workers earnings functionC //this === earnings;);
3. [Array: string] items for methods
The methods passed to thelist
loses their
this
reference to the object, they were declared in, what may be undesirable.
const workers = {} {};const list = workersaddWorker //this !== workers workerslistEarnings //this !== workers;
- to retain the
this
reference to the object, that the methods are declared in, push [Array] item with methods' [String] names into thelist
:- The
[0]
item should indicate the object, that the methods are declared in - The
[1]
,[2]
, etc... item(s) should indicate the [String] name(s) of the method(s) declared in the[0]
object
- The
- These methods retain the
this
reference to the[0]
object and are not bound to theconfig.context
- The
config.bind
setting does not affect thethis
reference - The [Array] item functions still have the access to the
config.context
parameter - the
list
can still contain the [Function] items or [Array] items with functions next to this [Array] item with [String] method's names - Samples: [sample]
const displayData = {};const workers = {} {};const list = workers 'addWorker' 'listEarnings' displayData ; );
config
[Object | null]
- the [Object]
config
argument allows to set the following config properties:timeout
,bind
,context
,passContext
- when the
config
is set tonull
or when it does not define the particular config property or when it defines the config property incorrectly, the default value is used for this config property instead [sample] [sample] [sample] - any error is thrown when any config property is defined incorrectly (the default value is used instead)
config.timeout
Type: [Number | null | Infinity]Default:
10000
Description:
- It must be a [Number] integer, equal or bigger than
0
, that indicates the milliseconds - it behaves different for each method:
-
moveOn
:
Theconfig.timeout
starts out counting down individually for each chained function immediately after it is called.
It expects each function to be resolved or rejected before timeout pass,
otherwise it calls thecatch
function with the timeout error argument passed -
moveOn.all
:
Theconfig.timeout
starts out counting down once for all chained functions when the module is fired.
It expects all functions to be resolved or any function to be rejected before timeout pass,
otherwise it calls thecatch
function with the timeout error argument passed -
moveOn.each
:
Theconfig.timeout
starts out counting down once for all chained functions when the module is fired.
It expects all functions to be either resolved or rejected before timeout pass,
otherwise it calls thecatch
function with the timeout error argument passed -
moveOn.first
:
Theconfig.timeout
starts out counting down once for all chained functions when the module is fired.
It expects at least one function to be resolved or all functions to be rejected before timeout pass,
otherwise it calls thecatch
function with the timeout error argument passed
-
- All
resolves
s andreject
s that are called after theconfig.timeout
pass are ignored - When the
config.timeout
is set tonull
orInfinity
, the timeout is not set at all. If any of the chained function does not resolve (or reject), anything happen then and thedone
orcatch
function is never called in the end - When the
config.timeout
is not defined, or if it is defined with incorrect value, the default value is set instead - Samples: [sample] [sample]
Timeout error
It is an [Error] object with the following properties, that allow to distinguish, that the timeout error has been passed:-
message
: eg."Timeout. The chained function did not respond in the expected time of 10000 ms."
-
info
:"timeout"
-
code
:"ETIMEDOUT"
config.context
Type: [any]
Default:
{}
Description:
- The
config.context
refers to the object (or value), that will be used as thethis
reference in alllist
functions,done
andcatch
- It is usefull to transmit data between functions; eg. the [Object]
config.context
's properties can be defined and got in any function - The
config.context
can be any value, as any value can be used as thethis
reference inFunction.prototype.bind
[read more] - The
config.context
is used as thethis
reference by default, unless you setconfig.bind
to false - The
config.context
is also accessible as the parameter, unless you setconfig.passContext
to false - Samples: [sample] [sample] [sample]
config.passContext
Type: [Boolean]
Default:
true
Description:
- By default, the
config.context
object (or value) is passed through eachlist
function, thedone
andcatch
as the argument: - In order not to pass the
config.context
as the argument, setconfig.passContext
tofalse
- The
config.context
accessible as the parameter is usefull:- if the
list
functions,done
orcatch
are arrow functions, that are non-binding and cannot refer to theconfig.context
viathis
keyword - if you compose the
list
with individually bound functions or methods names , that do not refer to theconfig.context
viathis
keyword - if
list
functions,done
orcatch
are already bound
- if the
- Samples: [sample] [sample]
config.bind
Type: [Boolean]
Default:
true
Description:
- By default, each
list
function,done
andcatch
are bound to theconfig.context
object (or value), thus thethis
keyword refers to theconfig.context
- In order to retain the former
this
reference of all functions, set theconfig.bind
tofalse
- In order to set the individual
this
reference for chosen functions, see thelist
constructing options -
keep in mind, that arrow functions are non-binding and that already bound functions cannot have the
this
reference changed anymore
done(
reject
,
context
)
[Function]
The
done
is a callback function, that
(in general) is called as the last one, when the
list
functions have been successfully executed. The
done
is called in a different way and time, depending on which method is called:
-
moveOn
Thedone
is called, when the last function from thelist
collection is resolved.
The arguments passed throughdone
:
[0]
reject
[1]
config.context
[2]
,[3]
, etc... The arguments passed by the last resolvedlist
function -
moveOn.all
Thedone
is called, when alllist
functions are resolved.
The arguments passed throughdone
:
[0]
reject
[1]
config.context
[2]
resolveMap
-
moveOn.each
Thedone
is called, when alllist
functions are either resolved or rejected.
The arguments passed throughdone
:
[0]
reject
[1]
config.context
[2]
resolveMap
-
moveOn.first
Thedone
is called, when the first (fastest)list
function is resolved.
The arguments passed throughdone
:
[0]
reject
[1]
config.context
[2]
,[3]
, etc... The arguments passed by the first (fastest) resolvedlist
function
resolveMap
object
- The
resolveMap
object is passed throughdone
callback when themoveOn.all
andmoveOn.each
method is executed. It stores all arguments that have been passed by eachlist
function'sresolve
call. - The
resolveMap
contains allarguments
objects at the indeces that correspond to the order oflist
functions calling; the thirdlist
function's arguments are accessible viaresolveMap[2]
, and so on... - The
resolveMap
properties:-
missing
It returns the [Array] list of thoselist
functions' indeces (due to the order of calling) that have not been resolved
-
- The
resolveMap
methods:-
forEach
It loops through eacharguments
object.
It expects the[0]
parameter to be the [Function] callback.
The [Function] callback is called for eacharguments
object.
The callback parameters:{0: arguments, 1: argumentsIndex, 2: resolveMap}
Usage:resolveMap.forEach((arguments, argumentsIndex, resolveMap) => {} );
-
forAll
It loops through each item (argument) of eacharguments
object.
It expects the[0]
parameter to be the [Function] callback.
The [Function] callback is called for each item (argument).
The callback parameters:{0: argument, 1: argumentsIndex, 2: itemIndex, 3: resolveMap}
Usage:resolveMap.forAll((argument, argumentsIndex, itemIndex, resolveMap) => {} );
-
- Samples: [sample] [sample]
catch(
context
)
[Function]
The
catch
is a callback function, that
(in general) is called as the last one, when the
list
function(s) have failed. The
catch
is called in a different way and time, depending on which method is called:
-
moveOn
Thecatch
is called, when anylist
function rejects.
The arguments passed throughcatch
:
[0]
config.context
[1]
,[2]
, etc... The arguments passed by the rejectedlist
function -
moveOn.all
Thecatch
is called, when anylist
function rejects.
The arguments passed throughcatch
:
[0]
config.context
[1]
,[2]
, etc... The arguments passed by the rejectedlist
function -
moveOn.each
Thecatch
is called for eachlist
function rejection.
The arguments passed throughcatch
:
[0]
config.context
[1]
,[2]
, etc... The arguments passed by the rejectedlist
function -
moveOn.first
Thecatch
is called, when alllist
function rejected.
The arguments passed throughcatch
:
[0]
config.context
[1]
rejectMap
rejectMap
object
- The
rejectMap
object is passed throughcatch
callback when themoveOn.first
method is executed. It stores all arguments that have been passed by alllist
functions'reject
calls - The
rejectMap
contains allarguments
objects at the indeces that correspond to the order oflist
functions calling; the thirdlist
function's arguments are accessible viarejectMap[2]
, and so on... - The
rejectMap
methods:-
forEach
It loops through eacharguments
object.
It expects the[0]
parameter to be the [Function] callback.
The [Function] callback is called for eacharguments
object.
The callback parameters:{0: arguments, 1: argumentsIndex, 2: rejectMap}
Usage:rejectMap.forEach((arguments, argumentsIndex, rejectMap) => {} );
-
forAll
It loops through each item (argument) of eacharguments
object.
It expects the[0]
parameter to be the [Function] callback.
The [Function] callback is called for each item (argument).
The callback parameters:{0: argument, 1: argumentsIndex, 2: itemIndex, 3: rejectMap}
Usage:rejectMap.forAll((argument, argumentsIndex, itemIndex, rejectMap) => {} );
-
Chained functions
- Each
list
function is called with the following arguments passed:-
[0]
resolve
callback function -
[1]
reject
callback function -
[2]
config.context
object (or value) -
[3]
,[4]
, etc... (formoveOn
method only) The arguments passed by the previouslist
function
-
- Both
resolve
andreject
can be called with any number of arguments [sample] [sample] [sample] [sample] - When the
resolve
is called with arguments, these arguments will be passed:-
moveOn
: for the furtherlist
function (or for thedone
function, when the lastlist
function resolves) -
moveOn.first
: for thedone
function -
moveOn.all
,moveOn.each
: for thedone
function in theresolveMap
object
-
- When the
reject
is called with arguments, these arguments will be passed:-
moveOn
,moveOn.all
,moveOn.each
: for thecatch
function -
moveOn.first
: for thecatch
function in therejectMap
object
-
{ this;}
Multiple
resolve
|
reject
calls
-
keep in mind that both
resolve
andreject
do not end function execution. In order to end function execution, usereturn resolve();
orreturn reject();
- the
moveOn.all
,moveOn.each
andmoveOn.first
methods expect thelist
functions to callresolve
orreject
once - the
moveOn
method, as it calls thelist
functions sequentially, accepts the multipleresolve
andreject
calls:- when the
list
function calls theresolve
twice, it runs the furtherlist
functions twice (the forks are created); theresolve
can be called eg. with different arguments - when the
list
function calls thereject
twice, it calls thecatch
twice; thereject
can be called eg. with different [Error] objects - when the
list
function calls bothresolve
andreject
, it both runs the furtherlist
functions and calls thecatch
- when the
- Samples: [sample] [sample]
inner
move-on
module
- the
list
function can also contain the innermove-on
module execution, that has thedone
argument set to theresolve
callback of thislist
function - Samples: [sample] [sample]
Code examples
1. The move-on
chain of synchronous and asynchronous functions
const moveOn = ;const list = requestData parseData displayData;const config = context: table: document //accessible in all functions as this.table ; ; //asynchronous { ;} //synchronous { thisdata = ; thisemployees = ; thisearnings = ; ;} { tableinnerHTML = ; ;} { thistablestyledisplay = "table";} { throw `Could not get the data: `;}
2. The move-on
module with the user config.context
and the arguments passed through the resolve
and reject
arrow callback functions
const moveOn = ; { console; //Jessica console; //25 //the [String] argument passed through the catch callback function if !thisname || !thisage return ; return ;} const config = context: name: 'Jessica' age: 25 ; ;
3. The move-on
module that rejects
Mind that the second rejected function ends up the execution of further chained functions.
const moveOn = ; ; { ;} { ;} { //it's been never called! ;} { //it's been never called!} { console; //oops!}
4. The move-on
instructions after resolve
call
In order to end up the chained function's execution, call return resolve();
const moveOn = ; ; /* logs order: A before B before C before Done! C after B after A after*/ { console; ; console;} { console; ; console;} { console; ; console;} { console;} { console; //oops!}
5. The inner move-on
module and multiple resolve
and reject
calls
Mind how X, Y and Z functions of the inner module execute between A, B and C chained functions.
Mind how the B and C chained functions are executed twice, by doubleresolve
call in A chained function.
const moveOn = ;;/* The order of functions execution: A, X, Y, Z, B, C, Done, Catch, B, C, Done, Catch */ { console; ; ;} { console; ;} { console; ; ;} { console; ;} { console; ;} { console; ;} { console;} { console;}
6. The move-on
.all
chain
It callsdone
callback function right after all chained functions are resolved.
The user's shorterconfig.timeout
is set.
Thereject
callback functions are not used. In case of error, thecatch
callback function will still be called withconfig.timeout
error.
All retrieved data is passed through theresolve
callback and accessible in theResolveMap
done
callback function.
const moveOn = ; const list = getArticle getTagList getCommentSection; moveOnalllist timeout: 5000 passContext: false onDone onCatch; { var xhr = ; xhr { if xhrreadyState == 4 && xhrstatus == 200 return ; }; xhr; xhr;} { var xhr = ; xhr { if xhrreadyState == 4 && xhrstatus == 200 return ; }; xhr; xhr;} { var xhr = ; xhr { if xhrreadyState == 4 && xhrstatus == 200 return ; }; xhr; xhr;} { let article = JSON; let tags = JSON; let comments = JSON;} { throw err;}
7. The move-on
.each
inner module
Themove-on
is used to get the files list asynchronously and then to copy all files asynchronously.
The innermove-on
.each
module is injected in the second chained function in order to report the success | failure message for each copied file.
Each copying failure occurrence callsreject
callback and logs the warning.
When all files are (un)successfully copied, thedone
callback function is called, that indicates the end of files copying action.
const moveOn = ;const fs = ;const path = ; const list = getContentsList copyFiles;const config = passContext: false context: copyFrom: './modules' copyTo: './prod/modules' ; ; { fs;} { const list = ; //the moveOn.each will take the same user context to get the access to the paths const config = context: this passContext: false ; //creating the list of chained functions for each files item: for let file of files list; //the inner moveOn.each module - as the done callback - calls the resolve callback of the second copyFiles function with [Resolved] map argument moveOn;} { //the [Resolved] map contains the collection of all passed files paths //the missing property contains the indeces of all moveOn.each chained functions that have been rejected let message = !mapmissinglength ? 'All files have been successfully moved.' : 'The files have been moved with some errors.'; console;} { throw err;}
8. The move-on
.first
module
It sends the request for the three urls and waits for the first (fastest) response.
const moveOn = ; ; { const list = urls = 'url-a' 'url-b' 'url-c' ; for let url of urls list //all list functions are called simultaneously //the module expects the first function to be resolved in order to call the done callback //if any of chained functions resolves in 2000ms, the timeout error will be passed through the catch callback function moveOn; { //the data has been passed by the fastest resolved chained function //the other chained functions are ignored } { throw err; //timeout error }}
9. The chain of class instance's methods
Theconfig.context
is set to the class instance'sthis
reference, thus the chained methods still have the access to all instance's properties and methods.
const moveOn = ; { const list = retrieveData createTable generateDiet; ; } { this; } { let data = this; thisvegetables = this; this; ; } { this; } { } { } { } { } { } { }
10. The email validation sample
Mind that chained functions are passed as [String] methods' names to retain the access to thethis
reference to the class instance.
Thedone
andcatch
calls the samecallback function
. Thereject
is used to terminate the further chained functions and theresolve
to continue execution. Mind that isString and isAvailable methods callreject
to stop the module execution.
The [Array]errorMessages
stores all validation error messages, that will be printed out for the user.
The isAvailable chained function is asynchronous and simulates the request sent to the server to check whether the email address is available.
const moveOn = ; { thisemail = email; thiserrorMessages = ; const list = this 'isString' 'hasAtSign' 'hasMultipleAtSigns' 'hasSpecialChars' 'hasCapitalLetters' 'hasSpaces' 'hasDoubleDots' 'isAvailable'; ; } { if typeof thisemail !== 'string' thiserrorMessages; return ; ; } { if !/@/ thiserrorMessages; ; } { if /@.*@/ thiserrorMessages; ; } { if !/^[A-z.\-@_]+$/ thiserrorMessages; ; } { if /[A-Z]/ thiserrorMessages; ; } { if /\s/ thiserrorMessages; ; } { if /\.{2,}/ thiserrorMessages; ; } { if thiserrorMessageslength return ; ; } const formInput = document;const formAlert = document;formInput;