UNPKG

npm

Version:

a package manager for JavaScript

1,192 lines (1,072 loc) 35.1 kB
/*! * async * https://github.com/caolan/async * * Copyright 2010-2014 Caolan McMahon * Released under the MIT license */ (function () { var async = {}; function noop() {} // global on the server, window in the browser var root, previous_async; if (typeof window == 'object' && this === window) { root = window; } else if (typeof global == 'object' && this === global) { root = global; } else { root = this; } if (root != null) { previous_async = root.async; } async.noConflict = function () { root.async = previous_async; return async; }; function only_once(fn) { var called = false; return function() { if (called) throw new Error("Callback was already called."); called = true; fn.apply(this, arguments); }; } function _once(fn) { var called = false; return function() { if (called) return; called = true; fn.apply(this, arguments); }; } //// cross-browser compatiblity functions //// var _toString = Object.prototype.toString; var _isArray = Array.isArray || function (obj) { return _toString.call(obj) === '[object Array]'; }; function _isArrayLike(arr) { return _isArray(arr) || ( // has a positive integer length property typeof arr.length === "number" && arr.length >= 0 && arr.length % 1 === 0 ); } function _each(coll, iterator) { return _isArrayLike(coll) ? _arrayEach(coll, iterator) : _forEachOf(coll, iterator); } function _arrayEach(arr, iterator) { var index = -1, length = arr.length; while (++index < length) { iterator(arr[index], index, arr); } } function _map(arr, iterator) { var index = -1, length = arr.length, result = Array(length); while (++index < length) { result[index] = iterator(arr[index], index, arr); } return result; } function _range(count) { return _map(Array(count), function (v, i) { return i; }); } function _reduce(arr, iterator, memo) { _arrayEach(arr, function (x, i, a) { memo = iterator(memo, x, i, a); }); return memo; } function _forEachOf(object, iterator) { _arrayEach(_keys(object), function (key) { iterator(object[key], key); }); } var _keys = Object.keys || function (obj) { var keys = []; for (var k in obj) { if (obj.hasOwnProperty(k)) { keys.push(k); } } return keys; }; function _keyIterator(coll) { var i = -1; var len; var keys; if (_isArrayLike(coll)) { len = coll.length; return function next() { i++; return i < len ? i : null; }; } else { keys = _keys(coll); len = keys.length; return function next() { i++; return i < len ? keys[i] : null; }; } } function _baseSlice(arr, start) { start = start || 0; var index = -1; var length = arr.length; if (start) { length -= start; length = length < 0 ? 0 : length; } var result = Array(length); while (++index < length) { result[index] = arr[index + start]; } return result; } function _withoutIndex(iterator) { return function (value, index, callback) { return iterator(value, callback); }; } //// exported async module functions //// //// nextTick implementation with browser-compatible fallback //// // capture the global reference to guard against fakeTimer mocks var _setImmediate; if (typeof setImmediate === 'function') { _setImmediate = setImmediate; } if (typeof process === 'undefined' || !(process.nextTick)) { if (_setImmediate) { async.nextTick = function (fn) { // not a direct alias for IE10 compatibility _setImmediate(fn); }; async.setImmediate = async.nextTick; } else { async.nextTick = function (fn) { setTimeout(fn, 0); }; async.setImmediate = async.nextTick; } } else { async.nextTick = process.nextTick; if (_setImmediate) { async.setImmediate = function (fn) { // not a direct alias for IE10 compatibility _setImmediate(fn); }; } else { async.setImmediate = async.nextTick; } } async.forEach = async.each = function (arr, iterator, callback) { return async.eachOf(arr, _withoutIndex(iterator), callback); }; async.forEachSeries = async.eachSeries = function (arr, iterator, callback) { return async.eachOfSeries(arr, _withoutIndex(iterator), callback); }; async.forEachLimit = async.eachLimit = function (arr, limit, iterator, callback) { return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback); }; async.forEachOf = async.eachOf = function (object, iterator, callback) { callback = _once(callback || noop); object = object || []; var size = _isArrayLike(object) ? object.length : _keys(object).length; var completed = 0; if (!size) { return callback(null); } _each(object, function (value, key) { iterator(object[key], key, only_once(done)); }); function done(err) { if (err) { callback(err); } else { completed += 1; if (completed >= size) { callback(null); } } } }; async.forEachOfSeries = async.eachOfSeries = function (obj, iterator, callback) { callback = _once(callback || noop); obj = obj || []; var nextKey = _keyIterator(obj); var key = nextKey(); function iterate() { var sync = true; if (key === null) { return callback(null); } iterator(obj[key], key, only_once(function (err) { if (err) { callback(err); } else { key = nextKey(); if (key === null) { return callback(null); } else { if (sync) { async.nextTick(iterate); } else { iterate(); } } } })); sync = false; } iterate(); }; async.forEachOfLimit = async.eachOfLimit = function (obj, limit, iterator, callback) { _eachOfLimit(limit)(obj, iterator, callback); }; function _eachOfLimit(limit) { return function (obj, iterator, callback) { callback = _once(callback || noop); obj = obj || []; var nextKey = _keyIterator(obj); if (limit <= 0) { return callback(null); } var done = false; var running = 0; var errored = false; (function replenish () { if (done && running <= 0) { return callback(null); } while (running < limit && !errored) { var key = nextKey(); if (key === null) { done = true; if (running <= 0) { callback(null); } return; } running += 1; iterator(obj[key], key, only_once(function (err) { running -= 1; if (err) { callback(err); errored = true; } else { replenish(); } })); } })(); }; } function doParallel(fn) { return function (obj, iterator, callback) { return fn(async.eachOf, obj, iterator, callback); }; } function doParallelLimit(limit, fn) { return function (obj, iterator, callback) { return fn(_eachOfLimit(limit), obj, iterator, callback); }; } function doSeries(fn) { return function (obj, iterator, callback) { return fn(async.eachOfSeries, obj, iterator, callback); }; } function _asyncMap(eachfn, arr, iterator, callback) { callback = _once(callback || noop); var results = []; eachfn(arr, function (value, index, callback) { iterator(value, function (err, v) { results[index] = v; callback(err); }); }, function (err) { callback(err, results); }); } async.map = doParallel(_asyncMap); async.mapSeries = doSeries(_asyncMap); async.mapLimit = function (arr, limit, iterator, callback) { return _mapLimit(limit)(arr, iterator, callback); }; function _mapLimit(limit) { return doParallelLimit(limit, _asyncMap); } // reduce only has a series version, as doing reduce in parallel won't // work in many situations. async.inject = async.foldl = async.reduce = function (arr, memo, iterator, callback) { async.eachOfSeries(arr, function (x, i, callback) { iterator(memo, x, function (err, v) { memo = v; callback(err); }); }, function (err) { callback(err || null, memo); }); }; async.foldr = async.reduceRight = function (arr, memo, iterator, callback) { var reversed = _map(arr, function (x) { return x; }).reverse(); async.reduce(reversed, memo, iterator, callback); }; function _filter(eachfn, arr, iterator, callback) { var results = []; arr = _map(arr, function (x, i) { return {index: i, value: x}; }); eachfn(arr, function (x, index, callback) { iterator(x.value, function (v) { if (v) { results.push(x); } callback(); }); }, function () { callback(_map(results.sort(function (a, b) { return a.index - b.index; }), function (x) { return x.value; })); }); } async.select = async.filter = doParallel(_filter); async.selectSeries = async.filterSeries = doSeries(_filter); function _reject(eachfn, arr, iterator, callback) { var results = []; arr = _map(arr, function (x, i) { return {index: i, value: x}; }); eachfn(arr, function (x, index, callback) { iterator(x.value, function (v) { if (!v) { results.push(x); } callback(); }); }, function () { callback(_map(results.sort(function (a, b) { return a.index - b.index; }), function (x) { return x.value; })); }); } async.reject = doParallel(_reject); async.rejectSeries = doSeries(_reject); function _detect(eachfn, arr, iterator, main_callback) { eachfn(arr, function (x, index, callback) { iterator(x, function (result) { if (result) { main_callback(x); main_callback = noop; } else { callback(); } }); }, function () { main_callback(); }); } async.detect = doParallel(_detect); async.detectSeries = doSeries(_detect); async.any = async.some = function (arr, iterator, main_callback) { async.eachOf(arr, function (x, _, callback) { iterator(x, function (v) { if (v) { main_callback(true); main_callback = noop; } callback(); }); }, function () { main_callback(false); }); }; async.all = async.every = function (arr, iterator, main_callback) { async.eachOf(arr, function (x, _, callback) { iterator(x, function (v) { if (!v) { main_callback(false); main_callback = noop; } callback(); }); }, function () { main_callback(true); }); }; async.sortBy = function (arr, iterator, callback) { async.map(arr, function (x, callback) { iterator(x, function (err, criteria) { if (err) { callback(err); } else { callback(null, {value: x, criteria: criteria}); } }); }, function (err, results) { if (err) { return callback(err); } else { callback(null, _map(results.sort(comparator), function (x) { return x.value; })); } }); function comparator(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; } }; async.auto = function (tasks, callback) { callback = _once(callback || noop); var keys = _keys(tasks); var remainingTasks = keys.length; if (!remainingTasks) { return callback(null); } var results = {}; var listeners = []; function addListener(fn) { listeners.unshift(fn); } function removeListener(fn) { for (var i = 0; i < listeners.length; i += 1) { if (listeners[i] === fn) { listeners.splice(i, 1); return; } } } function taskComplete() { remainingTasks--; _arrayEach(listeners.slice(0), function (fn) { fn(); }); } addListener(function () { if (!remainingTasks) { callback(null, results); } }); _arrayEach(keys, function (k) { var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; function taskCallback(err) { var args = _baseSlice(arguments, 1); if (args.length <= 1) { args = args[0]; } if (err) { var safeResults = {}; _arrayEach(_keys(results), function(rkey) { safeResults[rkey] = results[rkey]; }); safeResults[k] = args; callback(err, safeResults); } else { results[k] = args; async.setImmediate(taskComplete); } } var requires = task.slice(0, Math.abs(task.length - 1)) || []; // prevent dead-locks var len = requires.length; var dep; while (len--) { if (!(dep = tasks[requires[len]])) { throw new Error('Has inexistant dependency'); } if (_isArray(dep) && !!~dep.indexOf(k)) { throw new Error('Has cyclic dependencies'); } } function ready() { return _reduce(requires, function (a, x) { return (a && results.hasOwnProperty(x)); }, true) && !results.hasOwnProperty(k); } if (ready()) { task[task.length - 1](taskCallback, results); } else { addListener(listener); } function listener() { if (ready()) { removeListener(listener); task[task.length - 1](taskCallback, results); } } }); }; async.retry = function(times, task, callback) { var DEFAULT_TIMES = 5; var attempts = []; // Use defaults if times not passed if (typeof times === 'function') { callback = task; task = times; times = DEFAULT_TIMES; } // Make sure times is a number times = parseInt(times, 10) || DEFAULT_TIMES; function wrappedTask(wrappedCallback, wrappedResults) { function retryAttempt(task, finalAttempt) { return function(seriesCallback) { task(function(err, result){ seriesCallback(!err || finalAttempt, {err: err, result: result}); }, wrappedResults); }; } while (times) { attempts.push(retryAttempt(task, !(times-=1))); } async.series(attempts, function(done, data){ data = data[data.length - 1]; (wrappedCallback || callback)(data.err, data.result); }); } // If a callback is passed, run this as a controll flow return callback ? wrappedTask() : wrappedTask; }; async.waterfall = function (tasks, callback) { callback = _once(callback || noop); if (!_isArray(tasks)) { var err = new Error('First argument to waterfall must be an array of functions'); return callback(err); } if (!tasks.length) { return callback(); } function wrapIterator(iterator) { return function (err) { if (err) { callback.apply(null, arguments); } else { var args = _baseSlice(arguments, 1); var next = iterator.next(); if (next) { args.push(wrapIterator(next)); } else { args.push(callback); } ensureAsync(iterator).apply(null, args); } }; } wrapIterator(async.iterator(tasks))(); }; function _parallel(eachfn, tasks, callback) { callback = callback || noop; var results = _isArrayLike(tasks) ? [] : {}; eachfn(tasks, function (task, key, callback) { task(function (err) { var args = _baseSlice(arguments, 1); if (args.length <= 1) { args = args[0]; } results[key] = args; callback(err); }); }, function (err) { callback(err, results); }); } async.parallel = function (tasks, callback) { _parallel(async.eachOf, tasks, callback); }; async.parallelLimit = function(tasks, limit, callback) { _parallel(_eachOfLimit(limit), tasks, callback); }; async.series = function (tasks, callback) { callback = callback || noop; var results = _isArrayLike(tasks) ? [] : {}; async.eachOfSeries(tasks, function (task, key, callback) { task(function (err) { var args = _baseSlice(arguments, 1); if (args.length <= 1) { args = args[0]; } results[key] = args; callback(err); }); }, function (err) { callback(err, results); }); }; async.iterator = function (tasks) { function makeCallback(index) { function fn() { if (tasks.length) { tasks[index].apply(null, arguments); } return fn.next(); } fn.next = function () { return (index < tasks.length - 1) ? makeCallback(index + 1): null; }; return fn; } return makeCallback(0); }; async.apply = function (fn) { var args = _baseSlice(arguments, 1); return function () { return fn.apply( null, args.concat(_baseSlice(arguments)) ); }; }; function _concat(eachfn, arr, fn, callback) { var result = []; eachfn(arr, function (x, index, cb) { fn(x, function (err, y) { result = result.concat(y || []); cb(err); }); }, function (err) { callback(err, result); }); } async.concat = doParallel(_concat); async.concatSeries = doSeries(_concat); async.whilst = function (test, iterator, callback) { if (test()) { iterator(function (err) { if (err) { return callback(err); } async.whilst(test, iterator, callback); }); } else { callback(null); } }; async.doWhilst = function (iterator, test, callback) { iterator(function (err) { if (err) { return callback(err); } var args = _baseSlice(arguments, 1); if (test.apply(null, args)) { async.doWhilst(iterator, test, callback); } else { callback(null); } }); }; async.until = function (test, iterator, callback) { if (!test()) { iterator(function (err) { if (err) { return callback(err); } async.until(test, iterator, callback); }); } else { callback(null); } }; async.doUntil = function (iterator, test, callback) { iterator(function (err) { if (err) { return callback(err); } var args = _baseSlice(arguments, 1); if (!test.apply(null, args)) { async.doUntil(iterator, test, callback); } else { callback(null); } }); }; function _queue(worker, concurrency, payload) { if (concurrency == null) { concurrency = 1; } else if(concurrency === 0) { throw new Error('Concurrency must not be zero'); } function _insert(q, data, pos, callback) { if (callback != null && typeof callback !== "function") { throw new Error("task callback must be a function"); } q.started = true; if (!_isArray(data)) { data = [data]; } if(data.length === 0 && q.idle()) { // call drain immediately if there are no tasks return async.setImmediate(function() { q.drain(); }); } _arrayEach(data, function(task) { var item = { data: task, callback: callback || noop }; if (pos) { q.tasks.unshift(item); } else { q.tasks.push(item); } if (q.tasks.length === q.concurrency) { q.saturated(); } }); async.setImmediate(q.process); } function _next(q, tasks) { return function(){ workers -= 1; var args = arguments; _arrayEach(tasks, function (task) { task.callback.apply(task, args); }); if (q.tasks.length + workers === 0) { q.drain(); } q.process(); }; } var workers = 0; var q = { tasks: [], concurrency: concurrency, saturated: noop, empty: noop, drain: noop, started: false, paused: false, push: function (data, callback) { _insert(q, data, false, callback); }, kill: function () { q.drain = noop; q.tasks = []; }, unshift: function (data, callback) { _insert(q, data, true, callback); }, process: function () { if (!q.paused && workers < q.concurrency && q.tasks.length) { while(workers < q.concurrency && q.tasks.length){ var tasks = payload ? q.tasks.splice(0, payload) : q.tasks.splice(0, q.tasks.length); var data = _map(tasks, function (task) { return task.data; }); if (q.tasks.length === 0) { q.empty(); } workers += 1; var cb = only_once(_next(q, tasks)); worker(data, cb); } } }, length: function () { return q.tasks.length; }, running: function () { return workers; }, idle: function() { return q.tasks.length + workers === 0; }, pause: function () { q.paused = true; }, resume: function () { if (q.paused === false) { return; } q.paused = false; var resumeCount = Math.min(q.concurrency, q.tasks.length); // Need to call q.process once per concurrent // worker to preserve full concurrency after pause for (var w = 1; w <= resumeCount; w++) { async.setImmediate(q.process); } } }; return q; } async.queue = function (worker, concurrency) { var q = _queue(function (items, cb) { worker(items[0], cb); }, concurrency, 1); return q; }; async.priorityQueue = function (worker, concurrency) { function _compareTasks(a, b){ return a.priority - b.priority; } function _binarySearch(sequence, item, compare) { var beg = -1, end = sequence.length - 1; while (beg < end) { var mid = beg + ((end - beg + 1) >>> 1); if (compare(item, sequence[mid]) >= 0) { beg = mid; } else { end = mid - 1; } } return beg; } function _insert(q, data, priority, callback) { if (callback != null && typeof callback !== "function") { throw new Error("task callback must be a function"); } q.started = true; if (!_isArray(data)) { data = [data]; } if(data.length === 0) { // call drain immediately if there are no tasks return async.setImmediate(function() { q.drain(); }); } _arrayEach(data, function(task) { var item = { data: task, priority: priority, callback: typeof callback === 'function' ? callback : noop }; q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); if (q.tasks.length === q.concurrency) { q.saturated(); } async.setImmediate(q.process); }); } // Start with a normal queue var q = async.queue(worker, concurrency); // Override push to accept second parameter representing priority q.push = function (data, priority, callback) { _insert(q, data, priority, callback); }; // Remove unshift function delete q.unshift; return q; }; async.cargo = function (worker, payload) { return _queue(worker, 1, payload); }; function _console_fn(name) { return function (fn) { var args = _baseSlice(arguments, 1); fn.apply(null, args.concat([function (err) { var args = _baseSlice(arguments, 1); if (typeof console !== 'undefined') { if (err) { if (console.error) { console.error(err); } } else if (console[name]) { _arrayEach(args, function (x) { console[name](x); }); } } }])); }; } async.log = _console_fn('log'); async.dir = _console_fn('dir'); /*async.info = _console_fn('info'); async.warn = _console_fn('warn'); async.error = _console_fn('error');*/ async.memoize = function (fn, hasher) { var memo = {}; var queues = {}; hasher = hasher || function (x) { return x; }; function memoized() { var args = _baseSlice(arguments); var callback = args.pop(); var key = hasher.apply(null, args); if (key in memo) { async.nextTick(function () { callback.apply(null, memo[key]); }); } else if (key in queues) { queues[key].push(callback); } else { queues[key] = [callback]; fn.apply(null, args.concat([function () { memo[key] = _baseSlice(arguments); var q = queues[key]; delete queues[key]; for (var i = 0, l = q.length; i < l; i++) { q[i].apply(null, arguments); } }])); } } memoized.memo = memo; memoized.unmemoized = fn; return memoized; }; async.unmemoize = function (fn) { return function () { return (fn.unmemoized || fn).apply(null, arguments); }; }; function _times(mapper) { return function (count, iterator, callback) { mapper(_range(count), iterator, callback); }; } async.times = _times(async.map); async.timesSeries = _times(async.mapSeries); async.timesLimit = function (count, limit, iterator, callback) { return async.mapLimit(_range(count), limit, iterator, callback); }; async.seq = function (/* functions... */) { var fns = arguments; return function () { var that = this; var args = _baseSlice(arguments); var callback = args.slice(-1)[0]; if (typeof callback == 'function') { args.pop(); } else { callback = noop; } async.reduce(fns, args, function (newargs, fn, cb) { fn.apply(that, newargs.concat([function () { var err = arguments[0]; var nextargs = _baseSlice(arguments, 1); cb(err, nextargs); }])); }, function (err, results) { callback.apply(that, [err].concat(results)); }); }; }; async.compose = function (/* functions... */) { return async.seq.apply(null, Array.prototype.reverse.call(arguments)); }; function _applyEach(eachfn, fns /*args...*/) { function go() { var that = this; var args = _baseSlice(arguments); var callback = args.pop(); return eachfn(fns, function (fn, _, cb) { fn.apply(that, args.concat([cb])); }, callback); } if (arguments.length > 2) { var args = _baseSlice(arguments, 2); return go.apply(this, args); } else { return go; } } async.applyEach = function (/*fns, args...*/) { var args = _baseSlice(arguments); return _applyEach.apply(null, [async.eachOf].concat(args)); }; async.applyEachSeries = function (/*fns, args...*/) { var args = _baseSlice(arguments); return _applyEach.apply(null, [async.eachOfSeries].concat(args)); }; async.forever = function (fn, callback) { var done = only_once(callback || noop); var task = ensureAsync(fn); function next(err) { if (err) { return done(err); } task(next); } next(); }; function ensureAsync(fn) { return function (/*...args, callback*/) { var args = _baseSlice(arguments); var callback = args.pop(); args.push(function () { var innerArgs = arguments; if (sync) { async.setImmediate(function () { callback.apply(null, innerArgs); }); } else { callback.apply(null, innerArgs); } }); var sync = true; fn.apply(this, args); sync = false; }; } async.ensureAsync = ensureAsync; // Node.js if (typeof module !== 'undefined' && module.exports) { module.exports = async; } // AMD / RequireJS else if (typeof define !== 'undefined' && define.amd) { define([], function () { return async; }); } // included directly via <script> tag else { root.async = async; } }());