// Require the core node modules. var Bluebird = require( "bluebird" ); var chalk = require( "chalk" ); // ----------------------------------------------------------------------------------- // // ----------------------------------------------------------------------------------- // // Here, we have a series of asynchronous tasks that are required to aggregate some // result. For the sake of the demo, let's assume that each one of the tasks has to be // run in serial. (function someWorkflow( userID ) { var promise = Bluebird // In this approach, we're still going to pass the running-aggregate down // through the promise chain; but, instead of passing it explicitly, we're // going to pass it down IMPLICITLY as the THIS binding for all the promise // handlers. What this means is that each promise handler can leverage its // own this-binding as the reduction. // -- // NOTE: This is a feature of Bluebird, not promises in general. .bind({ userID: userID, user: null, subscription: null, projects: null }) .then( getUser ) .then( getSubscription ) .then( getProjects ) .then( function handleResolve() { // When outputting the results, notice that we're using the THIS // binding as the implicitly-passed running-aggregate. console.log( chalk.magenta( "User ID:" ), this.user.id ); console.log( chalk.magenta( "Subscription ID:" ), this.subscription.id ); console.log( chalk.magenta( "Project Count:" ), this.projects.length ); } ) .catch( function handleReject( reason ) { // This method has access to the "reduction" via "this". } ) .finally( function handleDone() { // This method has access to the "reduction" via "this". } ) ; })( 47 ); // Self-executing function block. // By using the IMPLICITLY-PASSED running aggregate, our workflow steps no longer need // to be in same closure as the workflow itself. This means that we don't have to // re-define the steps every time the workflow is executed; but, it does mean that each // individual step has to be responsible for updating the implicit aggregate. function getUser() { var promise = db_getUser( this.userID ).then( ( result ) => { // Store the result into the running aggregate which is being implicitly // passed down through the promise chain. this.user = result; } ); return( promise ); } function getSubscription() { var promise = db_getSubscription( this.user.accountID ).then( ( result ) => { // Store the result into the running aggregate which is being implicitly // passed down through the promise chain. this.subscription = result; } ); return( promise ); } function getProjects() { var promise = db_getProjects( this.user.id ).then( ( result ) => { // Store the result into the running aggregate which is being implicitly // passed down through the promise chain. this.projects = result; } ); return( promise ); } // ----------------------------------------------------------------------------------- // // ----------------------------------------------------------------------------------- // // Mock database access for user. function db_getUser( id ) { var user = { id: id, accountID: "AFC-9-3S", name: "Lisa" }; return( Bluebird.resolve( user ) ); } // Mock database access for subscription. function db_getSubscription( accountID ) { var subscription = { id: 97, accountID: accountID, startedAt: "2016-02-14" }; return( Bluebird.resolve( subscription ) ); } // Mock database access for projects. function db_getProjects( userID ) { var projects = [ "Project A", "Project B", "Project C" ]; return( Bluebird.resolve( projects ) ); }