ready.js
Watches over multiple async operations and triggers listeners when all or some are complete.
At only 854 bytes (gzip) ready.js is a powerful and tiny library that alllows you to manage and monitor multiple asynchronous operations, giving you total control of your application's execution flow.
Run ready.js on the browser or node.js!
Contents
Getting Started
Browser version
Get the latest browser version (0.7.0).
node.js version
npm install asyncready.js
(ready.js was taken).
var ready = ;
The Concept
- Each ready.js instance is a ready watch. Each watch can have one or multiple checks.
- All Checks have to finish in order to complete a watch.
- Listeners can be attached on the completion of a single check or the completion of the whole ready watch.
Assume we have 4 asynchronous operations that need to run, and we want to execute x(), y() and z() functions when all 4 are complete.
First, we'll create a ready watch, let's name it jobDone
.
var r = ss;
The async operations are 2 db writes, 1 db read and 1 file operation. We'll have to create 4 checks.
// our ready watch was stored in var rr; // we can get the same ready watch every time we call ss.ready('jobDone')ss // ... and chain our method calls ;
So, at this point we have created the ready watch ('jobDone') and added 4 checks ('db_write_one', 'db_write_two', 'db_read_one' and 'file_op_one').
Let's add some listeners on the watch.
// As per our scenario we want to execute x, y and z functions:var r = ss;r // chain chain chain ;
Awesome, we now have a ready watch with checks and listeners attached. Now, somewhere deep in our code, we do the async operations. When they are finished we want to inform our ready watch about it, so it knows when everything is finished and trigger the listeners.
// let's check db write one first...client; /* In the meantime... */ // A cool feature with checks is that every added check on our// ready watch creates a method with the name we used.// So for cases where we don't want to create an anon func// we can inline the check call like this:client; /* Let's finish this up now... */ // two remaining checks todo, remember to call the checks in any outcome// of your async operations, success or failure!client; // the file read operation...fs;
And that was it. Once all 4 checks are done, the ready watch will execute all attached listeners.
ready.js is pretty flexible, you can add listeners at any point in the lifespan of the watch and they will either queue up if the watch is not finished or if it's finished, synchronously execute.
Documentation
In the browser, you can find ready.js in the ss.ready
namespace, or if you run on node.js do a require('asyncready.js');
.
Documentation Contents
- ss.ready(name | function, opt_forceInit) : Get a new or existing ready instance.
- .addCheck(checkId) : Add a check to the ready watch.
- .check(checkId, var_args) : Mark a check as done.
- .addListener(fn, opt_selfObj) : Add a listener the ready watch completion.
- .addCheckListener(checkId, fn, opt_selfObj) : Add a listener on the completion of a specific check.
- .getArgs(checkId) : Get arguments passed to a check.
- .isDone(), .isCheckDone(checkId) : Query if a ready watch or a specific check have finished.
- .dispose() : Dispose all references of the ready instance.
- STATIC: ss.ready.reset() : Hard core delete action!
ss.ready(name | function, opt_forceInit)
Returns: Ready Instance
ss.ready
creates a new ready instance or returns an existing one if it was previously initialized.
The opt_forceInit
option is a boolean which if set to true, will force re-initialization of the watch. A nice example of how to use it can be found in Example 3.
If the first parameter is a function then ss.ready
poses as .addListener
and attaches to the 'main' watch. The main watch is hardcoded into the library and uses the name main
.
You can access the default 'main' watch with ss.ready('main')
or plainly ss.ready()
.addCheck(checkId)
Returns: Ready Instance
.addCheck(checkId)
adds a check to the ready watch. Make sure checkId
is a string or has a .toString()
method.
Each check that is added, has to be checked (aka finished) with the .check(checkId)
call.
addCheck
returns the self instance so you can chain it.
Every check you add creates a new method in the instance using the checkId
parameter as name. This new method is the same as calling .check(checkId)
. See the example...
var r = ss;r; r // let's try chaining... ; /* Do your stuff, add listeners, etc */ // facebook finishedr; // twitter finished, use the newly created// method to declare it's doner;// do the same with local authr;
.check(checkId, var_args)
Returns: Ready Instance
.check(checkId)
declares that a check has finished.
check
returns the self instance so you can chain it.
check
can trigger execution of listeners if it's the last one of the checks to finish or if we have attached a checkListener for this check.
You can pass any number or parameters and they can be accessed via the getArgs method.
.addListener(fn, opt_selfObj)
Returns: Ready Instance
Adds a listener for the completion of the current ready watch. fn
has to be a function.
addListener
returns the self instance so you can chain it.
Optionally you can set an object to apply on the executed listener.
Each listener that is executed gets passed the Ready Instance as a parameter. The Ready Instance is particularly usefull to query (getArgs) for the parameters that were passed on each check that was executed.
var r = ss;r;r;r; // When our app is ready execute allDone to cleanup and update UIss// load widgets when our app is ready ; // load calendar widget after app is ready ;
.addCheckListener(checkId, fn, opt_selfObj)
Returns: Ready Instance
Adds a listener for the completion of the specified check.
addCheckListener
returns the self instance so you can chain it.
Optionally you can set an object to apply on the executed listener.
Each Check listener that is executed has aguments as they were passed to the check call.
var r = ss;// add a checkr; // add a check listenerss // gotta love func expressions { status === true; // true message === 'foo'; // true too} /* ... */ // check the checkss;
.getArgs(checkId)
Returns: Array
Returns an array of arguments passed to a check identified by checkId.
var r = ss;r;r; // declare our listener function// 'ready' is the instance of the ready watchvar { // get auth resolution var authArgs = ready; authArgs0 === true; // true authArgs1 === nick: 'foo'; // also true (if only we could deep compare)}; ss; /* ... */// listen for DOM ready eventvar r = ss;jQuery; // our auth resolution function... { // stuff // more stuff // oh we have an authed user, run check and // declare it ss;}
.isDone(), .isCheckDone(checkId)
isDone
returns boolean
if the ready watch has finished.
isCheckDone
returns boolean
if the specified check has finished.
.dispose()
Will dispose all references to checks, listeners, everything, from the current instance.
STATIC: ss.ready.reset()
Hard core delete action!
Will run .dispose()
on all existing instances and remove any references to the instances.
Examples
Example 1: Our web application initializes...
{ /* do stuff */ // check if facebook authed us if ready0 // we are authed from FB } // we'll use the main event to attach the appReady callbackss; // load a few libs when app is readyss;ss; // now add the checks that we want to watchvar r = ss; // ready with no params, returns the default 'main' watch r ; // attach to document ready event using jQuery and inline execute DOM check; /* ... */ // Listen for Facebook initial login statusFB; /* ... */ // when our UI is ready and responsive trigger the ui checkss; /* ... */
Example 2: Listeners can be added after watch has finished
var r = ss;r;r; /* ... */ r;r; /* ... */ r;
Example 3: Ready watch inside a repeative callback
/** * A callback method for an ajax call to our * server that has loaded a set of users. * * We have to render them and emit an event when * all ui / ux is done * * @param * @return */usersprototype { // prepare our ready watch, force init as this is a repeative // call and we don't want to load previous state var r = ss; // add checks for our two main operations r r; // when all done execute _usersRenderFinished and apply // our current scope r; // go through all users var user userBlock; for var i = 0 l = allUserslength ; i < l ; i++ // get the single user data object user = allUsersi; // get the user markup block, from our awesome "class" userBlock = user; // userBlock needs to load the user's image // and appear with a small animation fx on the DOM // dynamically create ready checks for these events r; r; // now attach the the userBlock's exposed events userBlock; userBlock; // remember, checks are also assigned as methods on our ready instance. // // Our unique to this user, checkId ('user-image-loaded' + user.id) let's suppose // it evaluates to 'user-image-loaded-444'. So this string literal has also been // assigned as a method to the ready instance 'r'. // // This means we can access it at r['user-image-loaded-444'] and execute // it using r['user-image-loaded-444'](); // append our userBlock to the DOM ; // loop finished, check 'allParased' and pass the user array r;} /** * When our UI has finished rendering and UX is done * call this function * @param * @return */usersprototype { // re-enable our search button ; // get the users array var args = ready; var allUsers = args0; // now emmit an event that we are done ourEventEngine;};
License
Copyright (c) 2012 Thanasis Polychronakis Licensed under the APACHE2 license.