From 90a2946a3b7b7d7aaf8d4bb6f1fba53c7cc23d7b Mon Sep 17 00:00:00 2001 From: Sean Soong Date: Tue, 16 Oct 2012 23:57:48 +1300 Subject: [PATCH] address issue #41, replace process.nextTick(check) because that causes a race condition --- lib/step.js | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/step.js b/lib/step.js index b524a6a..6438b37 100755 --- a/lib/step.js +++ b/lib/step.js @@ -26,11 +26,15 @@ SOFTWARE. // modified to fit my taste and the node.JS error handling system. function Step() { var steps = Array.prototype.slice.call(arguments), - pending, counter, results, lock; + pending, counter, results, lock, + groupLocalCallback, groupCounter, groupPending, groupResult, groupError; // Define the main callback that's given as `this` to the steps. function next() { counter = pending = 0; + groupCounter = groupPending = 0; + groupLocalCallback = groupError = undefined; + groupResult = []; // Check if there are no steps left if (steps.length === 0) { @@ -54,12 +58,20 @@ function Step() { next(e); } + if (groupCounter > 0 && groupPending == 0) { // all group() are called synchronously + groupLocalCallback(groupError, groupResult); // because groupLocalCallback() is called with lock == true, we delay next() call to next stanza + } else if (groupCounter == 0 && groupLocalCallback) { // after var group = this.group(), didn't call any group() + next(undefined, []); + lock = false; + return; + } + if (counter > 0 && pending == 0) { // If parallel() was called, and all parallel branches executed // synchronously, go on to the next step immediately. next.apply(null, results); } else if (result !== undefined) { - // If a synchronous return is used, pass it to the callback + // If a syncronous return is used, pass it to the callback next(undefined, result); } lock = false; @@ -87,32 +99,27 @@ function Step() { // Generates a callback generator for grouped results next.group = function () { - var localCallback = next.parallel(); - var counter = 0; - var pending = 0; - var result = []; - var error = undefined; + groupLocalCallback = next.parallel(); function check() { - if (pending === 0) { + if (groupPending === 0) { // When group is done, call the callback - localCallback(error, result); + groupLocalCallback(groupError, groupResult); } } - process.nextTick(check); // Ensures that check is called at least once // Generates a callback for the group return function () { - var index = counter++; - pending++; + var index = groupCounter++; + groupPending++; return function () { - pending--; + groupPending--; // Compress the error from any result to the first argument if (arguments[0]) { - error = arguments[0]; + groupError = arguments[0]; } // Send the other results as arguments - result[index] = arguments[1]; + groupResult[index] = arguments[1]; if (!lock) { check(); } }; }; @@ -140,10 +147,9 @@ Step.fn = function StepFn() { toRun.push(args.pop()); } - Step.apply(null, toRun); - } -} + }; +}; // Hook into commonJS module systems