Created
December 23, 2015 03:53
-
-
Save cmawhorter/86c576a597479ba366bc to your computer and use it in GitHub Desktop.
Wait for all values in state to be true before calling callback or error on timeout.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// similar usecase; abbreviated | |
var myTask = function(callback) { | |
var state = { response: false, body: false, other: null }; // only t/f factored when enableNulls | |
var abortWait = waitForState(state, callback); // returns function to abort with error | |
var req = request('https://...'); | |
req.on('response', function(res) { | |
asyncLogResponse(function(err) { | |
if (err) return abortWait(err); // aborts wait and callbacks immediately | |
state.response = true; | |
}); | |
}); | |
// ... similar for state.body ... | |
// once both return invokes callback or an error if it times out (after 60s) | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// License: Public Domain or MIT | |
// wraps async.until specifically for this usecase; with some options | |
var async = require('async'); | |
function waitForState(state, options, callback) { | |
if (typeof options === 'function') { | |
callback = options; | |
options = {}; | |
} | |
var timeout = options.timeout || 60000 | |
, pollEvery = options.pollEvery || 1000 | |
, enableNulls = typeof options.enableNulls === 'boolean' ? options.enableNulls : true | |
, log = options.log || function(){} | |
, start = new Date().getTime() | |
, _aborted = false; | |
log('waitForState options', timeout, pollEvery, enableNulls); | |
log('started at', start); | |
async.until(function() { | |
if (_aborted) { | |
return true; | |
} | |
log('entering state test'); | |
var workIsComplete = true; | |
for (var k in state) { | |
var val = state[k]; | |
log('\t-> iterating %s = %s', k, val); | |
if (!enableNulls || null !== val) { | |
log('\t-> testing %s = %s', k, val); | |
workIsComplete = workIsComplete && val; | |
log('\t<- complete?', workIsComplete); | |
} | |
} | |
log('leaving state test', workIsComplete); | |
return workIsComplete; | |
}, function(taskCallback) { | |
setTimeout(function() { | |
var elapsed = new Date().getTime() - start | |
, isTimedOut = elapsed < timeout; | |
log('entering task'); | |
log('\t-> elapsed %s less than timeout %s?', elapsed, timeout, isTimedOut); | |
taskCallback(isTimedOut ? null : new Error('timed out while waiting for state')); | |
}, pollEvery); | |
}, function() { | |
if (!_aborted) { | |
callback.apply(this, arguments); | |
} | |
}); | |
return function abortWaitForState(err) { | |
_aborted = true; | |
callback(err || new Error('wait aborted')); | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// caolan/async has a lot but it doesn't have a baked in way to to do this? | |
// Example usecase: | |
// You have a task that is reading from a remote stream and need to do an async log | |
// multiple times along the way. How can you be sure all logs completed successfully | |
// before invoking the callback? | |
var myTask = function(callback) { | |
var req = request('https://...'); | |
req.on('response', asyncLogResponse); | |
req.on('error', asyncLogError); | |
req.pipe(asyncLogBodyStream).on('end', asyncLogEnd); | |
// when can we invoke callback() ? | |
// async.parallel would work, unless one of our async tasks never returns | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment