From 01d71f1d1dba6970fcaa07c813bedcb4f75abbf0 Mon Sep 17 00:00:00 2001 From: Deepak N Date: Sat, 23 Apr 2011 19:12:56 +0530 Subject: [PATCH 1/2] Adding callback support to MULTI, so that return value of a async MULTI function can be processed without depending on the order of arguments in final step. --- README.md | 17 +++++++++++++++++ flow.js | 3 ++- tests.js | 22 +++++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3437cf8..525b5ac 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,23 @@ Here is an example of `this.MULTI()` in action (repeated from the overview): } ); + You can process the arguments returned from function by passing a callback to MULTI. The next step in the flow is executed only after the callback passed to MULTI is invoked. + + Example: + + flow.exec( + function() { + dbGet('userIdOf:bobvance', this.MULTI(function(userId){ + dbSet('user:' + userId + ':email', 'bobvance@potato.egg'); + })); + dbGet('userIdOf:joohndoe', this.MULTI(function(userId){ + dbSet('user:' + userId + ':email', 'joohndoe@potato.egg'); + }); + },function(argsArray) { + okWeAreDone() + } + ); + In many cases, you may simply discard the arguments passed to each of the callbacks generated by `this.MULTI()`, but if you need them, they are accessible as an array of `arguments` objects passed as the first argument of the next function. Each `arguments` object will be diff --git a/flow.js b/flow.js index 771c8da..d82d54e 100644 --- a/flow.js +++ b/flow.js @@ -58,11 +58,12 @@ // MULTI can be used to generate callbacks that must ALL be called before the next step // in the flow is executed. Arguments to those callbacks are accumulated, and an array of // of those arguments objects is sent as the one argument to the next step in the flow. - flowState.MULTI = function() { + flowState.MULTI = function(callback) { flowState.__multiCount += 1; return function() { flowState.__multiCount -= 1; flowState.__multiOutputs.push(arguments); + if (callback) callback.apply(this, arguments); if (flowState.__multiCount === 0) { var multiOutputs = flowState.__multiOutputs; diff --git a/tests.js b/tests.js index f6395f2..86cf07f 100644 --- a/tests.js +++ b/tests.js @@ -4,7 +4,7 @@ var keystore = require('./examples/keystore'); var flowsComplete = 0; setTimeout(function() { - var expected = 3; + var expected = 4; assert.strictEqual(flowsComplete, expected, flowsComplete + "/" + expected +" flows finished"); }, 1000); @@ -34,6 +34,26 @@ flow.exec( } ); +// MULTI with callback test +var fetchedFirstName, fetchedLastName; +flow.exec( + function() { + var db = keystore.getDb(); + db.firstName = "Bob" + db.lastName = "Vance" + keystore.get("firstName", this.MULTI(function(error, value){ + fetchedFirstName = value; + })); + keystore.get("lastName", this.MULTI(function(error, value){ + fetchedLastName = value; + })); + },function() { + assert.strictEqual(fetchedFirstName, "Bob", "multi with callback test didn't work"); + assert.strictEqual(fetchedLastName, "Vance", "multi with callback test didn't work"); + flowsComplete += 1; + } +); + // serialForEach test var valueSequence = []; flow.serialForEach([1, 2, 3, 4], function(val) { From 99a05fadd024c5246ab1712e69de3e37d6ea7151 Mon Sep 17 00:00:00 2001 From: Deepak N Date: Sat, 7 May 2011 16:31:09 +0530 Subject: [PATCH 2/2] MULTI can take identfier to get the result of a function in the last step --- README.md | 16 +++++++--------- examples/keystore.js | 8 ++++++++ flow.js | 9 +++++++-- tests.js | 37 +++++++++++++++++++++++-------------- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 525b5ac..d5964d1 100644 --- a/README.md +++ b/README.md @@ -173,20 +173,18 @@ Here is an example of `this.MULTI()` in action (repeated from the overview): } ); - You can process the arguments returned from function by passing a callback to MULTI. The next step in the flow is executed only after the callback passed to MULTI is invoked. + You can identify the results of a function by passing a result identifier to MULTI. The results of a function can retrieved using this key in the final step. The result will be a single value if callback receives 0 or 1 argument, otherwise it will be an array of arguments passed to the callback. Example: flow.exec( function() { - dbGet('userIdOf:bobvance', this.MULTI(function(userId){ - dbSet('user:' + userId + ':email', 'bobvance@potato.egg'); - })); - dbGet('userIdOf:joohndoe', this.MULTI(function(userId){ - dbSet('user:' + userId + ':email', 'joohndoe@potato.egg'); - }); - },function(argsArray) { - okWeAreDone() + dbGet('userIdOf:bobvance', this.MULTI('bob')); + dbGet('userIdOf:joohndoe', this.MULTI('john')); + },function(results) { + dbSet('user:' + results['bob'] + ':email', 'bobvance@potato.egg'); + dbSet('user:' + results['john'] + ':email', 'joohndoe@potato.egg'); + okWeAreDone(); } ); diff --git a/examples/keystore.js b/examples/keystore.js index fee19bf..3adf2c9 100644 --- a/examples/keystore.js +++ b/examples/keystore.js @@ -31,6 +31,14 @@ exports.get = function(key, callback) { }, 100); } +// keystore.exists(key, callback) +// callback signature: (value) +exports.exists = function(key, callback) { + setTimeout(function() { + if (callback) callback(key in db); + }, 100); +} + // keystore.increment(key, incrementBy, callback) // callback signature: (error, newValue) exports.increment = function(key, incrementBy, callback) { diff --git a/flow.js b/flow.js index d82d54e..9d92de0 100644 --- a/flow.js +++ b/flow.js @@ -58,12 +58,17 @@ // MULTI can be used to generate callbacks that must ALL be called before the next step // in the flow is executed. Arguments to those callbacks are accumulated, and an array of // of those arguments objects is sent as the one argument to the next step in the flow. - flowState.MULTI = function(callback) { + // @param {String} resultId An identifier to get the result of a multi call. + flowState.MULTI = function(resultId) { flowState.__multiCount += 1; return function() { flowState.__multiCount -= 1; flowState.__multiOutputs.push(arguments); - if (callback) callback.apply(this, arguments); + + if (resultId) { + var result = arguments.length <= 1 ? arguments[0] : arguments + flowState.__multiOutputs[resultId] = result; + } if (flowState.__multiCount === 0) { var multiOutputs = flowState.__multiOutputs; diff --git a/tests.js b/tests.js index 86cf07f..019a0fe 100644 --- a/tests.js +++ b/tests.js @@ -4,7 +4,7 @@ var keystore = require('./examples/keystore'); var flowsComplete = 0; setTimeout(function() { - var expected = 4; + var expected = 5; assert.strictEqual(flowsComplete, expected, flowsComplete + "/" + expected +" flows finished"); }, 1000); @@ -34,22 +34,31 @@ flow.exec( } ); -// MULTI with callback test -var fetchedFirstName, fetchedLastName; +// MULTI with result identifier test flow.exec( function() { var db = keystore.getDb(); - db.firstName = "Bob" - db.lastName = "Vance" - keystore.get("firstName", this.MULTI(function(error, value){ - fetchedFirstName = value; - })); - keystore.get("lastName", this.MULTI(function(error, value){ - fetchedLastName = value; - })); - },function() { - assert.strictEqual(fetchedFirstName, "Bob", "multi with callback test didn't work"); - assert.strictEqual(fetchedLastName, "Vance", "multi with callback test didn't work"); + db['firstName'] = "Bob" + db['lastName'] = "Vance" + keystore.get("firstName", this.MULTI('first-name')); + keystore.get("lastName", this.MULTI('last-name')); + },function(results) { + assert.strictEqual(results['first-name'][1], "Bob", "multi with result identifier test didn't work"); + assert.strictEqual(results['last-name'][1], "Vance", "multi with result identifier test didn't work"); + flowsComplete += 1; + } +); + +// MULTI with result identifier for single return value test +flow.exec( + function() { + var db = keystore.getDb(); + db['bob'] = "Bob Vance" + keystore.exists("bob", this.MULTI('bob-exists')); + keystore.exists("john", this.MULTI('john-exists')); + },function(results) { + assert.strictEqual(results['bob-exists'], true, "multi with result identifier for single return value test didn't work"); + assert.strictEqual(results['john-exists'], false, "multi with result identifier for single return value test didn't work"); flowsComplete += 1; } );