Skip to content

Organize your library or project, defining flows composable by a sequence of units

License

Notifications You must be signed in to change notification settings

alumna/unitflow

Repository files navigation

unitflow
Organize your library or project, defining flows composable by a sequence of units

Introducing Unitflow

Easily orgnize complex libraries in Javascript

UnitFlow can be used on any type of project, but it is aimed to be used when building libraries.

It's common to find yourself racking your brain to translate into code a complex sequence of different activities. Also, it is even more difficult to maintain and grow a code like that.

UnitFlow is a response to this problem. It gives a tangible approach to organize all the workflow of your library or project by making the sequence of activities more visual on your code.

Key Features

  • Extremely lightweight with no dependencies – 1.3kB!
  • Fully asynchronous, non-blocking and reactive

How UnitFlow works

  • A flow is a sequence of units
  • Units are functions with isolated pieces of the logic your library must execute
  • After defining a unit, you can use it in as many flows as you want, one or many
  • You can define multiple flows with no limits of units in each one
  • Each unit is always called with two arguments: state and next
  • state is a writable object available to all units and can (optionally) be initialized with upfront data
  • next is the function to be called (without arguments) inside the unit when its work is done
  • A unit can create new flows or call existing ones, allowing the organization of really complex scenarios
  • Units that create or call flows can retrieve their instance with the keyword this to do so
  • Each unit can specify execution dependencies on other units
  • Units with dependencies will be called only after their dependencies have completed
  • You can run multiple flows in parallel and define dependencies between different units on different flows

Extra beneficts

  • Each flow's run returns a promise that resolves after all its units have completed
  • Units waiting its dependencies remain non-active and do not consume memory or processing

Install

$ npm install @alumna/unitflow

Additionally, this module is delivered as:

Usage: single flow

import { Unitflow } from '@alumna/unitflow';

// create an instance
const mylib = new Unitflow({ /* optional data for initial state */ });

// defining units
mylib.unit[ 'unit_1' ] = function ( state, next ) { /* ... */ }
mylib.unit[ 'unit_2' ] = function ( state, next ) { /* ... */ }

// defining a flow
mylib.flow[ 'flow_1' ] = [ 'unit_1', 'unit_2' ]

// running a single flow
mylib.run( 'flow_1' )

Special third argument end

In any unit you can optionally end a flow using the third argument end. When calling it, flow will not continue:

import { Unitflow } from '@alumna/unitflow';

// create an instance
const mylib = new Unitflow();

// defining units
mylib.unit[ 'unit_1' ] = function ( state, next, end ) {
	
	// If true, the flow will stop and unit_2 will not be called
	if ( something_bad_happens == true )
		return end();
}

mylib.unit[ 'unit_2' ] = function ( state, next ) { /* ... */ }

// defining a flow
mylib.flow[ 'flow_1' ] = [ 'unit_1', 'unit_2' ]

// running a single flow
mylib.run( 'flow_1' )

Usage: multiple flows

import { Unitflow } from '@alumna/unitflow';

// create an instance
const mylib = new Unitflow({ /* optional data for initial state */ });

// defining units
mylib.unit[ 'unit_1' ] = function ( state, next ) { /* ... */ }
mylib.unit[ 'unit_2' ] = function ( state, next ) { /* ... */ }
mylib.unit[ 'unit_3' ] = function ( state, next ) { /* ... */ }
mylib.unit[ 'unit_4' ] = function ( state, next ) { /* ... */ }

// defining the flows
mylib.flow[ 'flow_1' ] = [ 'unit_1', 'unit_2' ]
mylib.flow[ 'flow_2' ] = [ 'unit_3', 'unit_4' ]

// running multiple flows in parallel
mylib.run( 'flow_1', 'flow_2' )

Defining execution dependencies

Even though everything runs asynchronously on Unitflow, optionally you can define dependencies between specific units to ensure that a unit with one or more dependencies will only start after all of them have completed

// considering the last example, but changing the "run" call, where
// the second argument is defining the execution dependencies

mylib.run( 'flow_1', 'flow_2', {

	// The "unit_4" on "flow_2" must be executed only after the "unit_2" on "flow_1"
	'flow_2:unit_4': [ 'flow_1:unit_2' ]

})

About

Organize your library or project, defining flows composable by a sequence of units

Resources

License

Stars

Watchers

Forks

Packages

No packages published