You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
4.5 KiB
199 lines
4.5 KiB
'use strict' |
|
|
|
var xtend = require('xtend') |
|
var reusify = require('reusify') |
|
var defaults = { |
|
released: nop, |
|
results: true |
|
} |
|
|
|
function fastparallel (options) { |
|
options = xtend(defaults, options) |
|
|
|
var released = options.released |
|
var queue = reusify(options.results ? ResultsHolder : NoResultsHolder) |
|
var queueSingleCaller = reusify(SingleCaller) |
|
var goArray = options.results ? goResultsArray : goNoResultsArray |
|
var goFunc = options.results ? goResultsFunc : goNoResultsFunc |
|
|
|
return parallel |
|
|
|
function parallel (that, toCall, arg, done) { |
|
var holder = queue.get() |
|
done = done || nop |
|
if (toCall.length === 0) { |
|
done.call(that) |
|
released(holder) |
|
} else { |
|
holder._callback = done |
|
holder._callThat = that |
|
holder._release = release |
|
|
|
if (typeof toCall === 'function') { |
|
goFunc(that, toCall, arg, holder) |
|
} else { |
|
goArray(that, toCall, arg, holder) |
|
} |
|
|
|
if (holder._count === 0) { |
|
holder.release() |
|
} |
|
} |
|
} |
|
|
|
function release (holder) { |
|
queue.release(holder) |
|
released(holder) |
|
} |
|
|
|
function singleCallerRelease (holder) { |
|
queueSingleCaller.release(holder) |
|
} |
|
|
|
function goResultsFunc (that, toCall, arg, holder) { |
|
var singleCaller = null |
|
holder._count = arg.length |
|
holder._results = new Array(holder._count) |
|
for (var i = 0; i < arg.length; i++) { |
|
singleCaller = queueSingleCaller.get() |
|
singleCaller._release = singleCallerRelease |
|
singleCaller.parent = holder |
|
singleCaller.pos = i |
|
if (that) { |
|
toCall.call(that, arg[i], singleCaller.release) |
|
} else { |
|
toCall(arg[i], singleCaller.release) |
|
} |
|
} |
|
} |
|
|
|
function goResultsArray (that, funcs, arg, holder) { |
|
var sc = null |
|
var tc = nop |
|
holder._count = funcs.length |
|
holder._results = new Array(holder._count) |
|
for (var i = 0; i < funcs.length; i++) { |
|
sc = queueSingleCaller.get() |
|
sc._release = singleCallerRelease |
|
sc.parent = holder |
|
sc.pos = i |
|
tc = funcs[i] |
|
if (that) { |
|
if (tc.length === 1) tc.call(that, sc.release) |
|
else tc.call(that, arg, sc.release) |
|
} else { |
|
if (tc.length === 1) tc(sc.release) |
|
else tc(arg, sc.release) |
|
} |
|
} |
|
} |
|
|
|
function goNoResultsFunc (that, toCall, arg, holder) { |
|
holder._count = arg.length |
|
for (var i = 0; i < arg.length; i++) { |
|
if (that) { |
|
toCall.call(that, arg[i], holder.release) |
|
} else { |
|
toCall(arg[i], holder.release) |
|
} |
|
} |
|
} |
|
|
|
function goNoResultsArray (that, funcs, arg, holder) { |
|
var toCall = null |
|
holder._count = funcs.length |
|
for (var i = 0; i < funcs.length; i++) { |
|
toCall = funcs[i] |
|
if (that) { |
|
if (toCall.length === 1) { |
|
toCall.call(that, holder.release) |
|
} else { |
|
toCall.call(that, arg, holder.release) |
|
} |
|
} else { |
|
if (toCall.length === 1) { |
|
toCall(holder.release) |
|
} else { |
|
toCall(arg, holder.release) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
function NoResultsHolder () { |
|
this._count = -1 |
|
this._callback = nop |
|
this._callThat = null |
|
this._release = null |
|
this.next = null |
|
|
|
var that = this |
|
var i = 0 |
|
this.release = function () { |
|
var cb = that._callback |
|
if (++i === that._count || that._count === 0) { |
|
if (that._callThat) { |
|
cb.call(that._callThat) |
|
} else { |
|
cb() |
|
} |
|
that._callback = nop |
|
that._callThat = null |
|
that._release(that) |
|
i = 0 |
|
} |
|
} |
|
} |
|
|
|
function SingleCaller () { |
|
this.pos = -1 |
|
this._release = nop |
|
this.parent = null |
|
this.next = null |
|
|
|
var that = this |
|
this.release = function (err, result) { |
|
that.parent.release(err, that.pos, result) |
|
that.pos = -1 |
|
that.parent = null |
|
that._release(that) |
|
} |
|
} |
|
|
|
function ResultsHolder () { |
|
this._count = -1 |
|
this._callback = nop |
|
this._results = null |
|
this._err = null |
|
this._callThat = null |
|
this._release = nop |
|
this.next = null |
|
|
|
var that = this |
|
var i = 0 |
|
this.release = function (err, pos, result) { |
|
that._err = that._err || err |
|
if (pos >= 0) { |
|
that._results[pos] = result |
|
} |
|
var cb = that._callback |
|
if (++i === that._count || that._count === 0) { |
|
if (that._callThat) { |
|
cb.call(that._callThat, that._err, that._results) |
|
} else { |
|
cb(that._err, that._results) |
|
} |
|
that._callback = nop |
|
that._results = null |
|
that._err = null |
|
that._callThat = null |
|
i = 0 |
|
that._release(that) |
|
} |
|
} |
|
} |
|
|
|
function nop () { } |
|
|
|
module.exports = fastparallel
|
|
|