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.
200 lines
4.5 KiB
200 lines
4.5 KiB
5 years ago
|
'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
|