Comparing version
31
index.js
@@ -1,4 +0,11 @@ | ||
var acomb = module.exports = {}; | ||
var acomb = exports; | ||
var _slice = [].slice; | ||
var _nextTick = setImmediate; | ||
if (!_nextTick) { // browsers | ||
_nextTick = function (fn) { | ||
setTimeout(fn, 0); | ||
}; | ||
} | ||
acomb.constant = function constant(value) { | ||
@@ -111,2 +118,18 @@ return function (callback) { | ||
acomb.ensureAsync = function ensureAsync(func) { | ||
return function (/*args..., cb*/) { | ||
var args = _initial(arguments); | ||
var cb = _last(arguments); | ||
var sameStack = true; | ||
args.push(function () { | ||
if (sameStack) { | ||
return _defer(cb, arguments); | ||
} | ||
cb.apply(null, arguments); | ||
}); | ||
func.apply(this, args); | ||
sameStack = false; | ||
}; | ||
}; | ||
function _last(arr) { | ||
@@ -123,1 +146,7 @@ return arr[arr.length - 1]; | ||
} | ||
function _defer(fn, args) { | ||
_nextTick(function () { | ||
fn.apply(null, args); | ||
}); | ||
} |
{ | ||
"name": "acomb", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Higher-order utilities for use with async functions", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -17,2 +17,3 @@ # acomb [](https://travis-ci.org/aearly/acomb) [](https://www.npmjs.org/package/acomb) | ||
* [provided](#provided) | ||
* [ensureAsync](#ensureAsync) | ||
@@ -108,3 +109,3 @@ <a name="constant"> | ||
Run a synchronous function before an async function. The synchronous function will be called with the aguments passed (without the callback), and the async function will be called with the return value of the sync function. | ||
Run a synchronous function before an async function. The synchronous function will be called with the arguments passed (without the callback), and the async function will be called with the return value of the sync function. | ||
@@ -154,5 +155,22 @@ ```js | ||
<a name="ensureAsync"> | ||
### ensureAsync(func) | ||
Ensure that an async function will always call its callback on a later tick in the event loop. No extra deferrals are added if the function passed does indeed callback asynchronously. This is useful for preventing stack overflows in things like `async.each`. | ||
```js | ||
async.map( | ||
Array(100000) | ||
acomb.ensureAsync(function (value, cb) { | ||
if (value < 50000) { | ||
return callback(null, value); // this function sometimes is synchronous! | ||
} | ||
doSomethingAsync(value, callback); | ||
}), | ||
callback | ||
); // no stack overflows! | ||
``` | ||
## License | ||
MIT |
32
test.js
@@ -188,2 +188,34 @@ var a = require("./"); | ||
}); | ||
describe("ensureAsync", function () { | ||
it("should defer if a sync function is passed", function (done) { | ||
var sameStack = true; | ||
a.ensureAsync(function (cb) { | ||
cb(); | ||
})(function () { | ||
assert(!sameStack); | ||
done(); | ||
}); | ||
sameStack = false; | ||
}); | ||
it("should not defer async functions", function (done) { | ||
var sameStack; | ||
a.ensureAsync(function (arg, cb) { | ||
assert(arg === 234); | ||
setTimeout(function () { | ||
sameStack = true; | ||
cb(123, 456); | ||
sameStack = false; | ||
}, 0); | ||
})(234, function (err, result) { | ||
assert(err === 123); | ||
assert(result === 456); | ||
assert(sameStack); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |
16396
13.4%338
19.01%174
11.54%