| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 | 'use strict';Object.defineProperty(exports, "__esModule", {    value: true});exports.default = auto;var _once = require('./internal/once.js');var _once2 = _interopRequireDefault(_once);var _onlyOnce = require('./internal/onlyOnce.js');var _onlyOnce2 = _interopRequireDefault(_onlyOnce);var _wrapAsync = require('./internal/wrapAsync.js');var _wrapAsync2 = _interopRequireDefault(_wrapAsync);var _promiseCallback = require('./internal/promiseCallback.js');function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }/** * Determines the best order for running the {@link AsyncFunction}s in `tasks`, based on * their requirements. Each function can optionally depend on other functions * being completed first, and each function is run as soon as its requirements * are satisfied. * * If any of the {@link AsyncFunction}s pass an error to their callback, the `auto` sequence * will stop. Further tasks will not execute (so any other functions depending * on it will not run), and the main `callback` is immediately called with the * error. * * {@link AsyncFunction}s also receive an object containing the results of functions which * have completed so far as the first argument, if they have dependencies. If a * task function has no dependencies, it will only be passed a callback. * * @name auto * @static * @memberOf module:ControlFlow * @method * @category Control Flow * @param {Object} tasks - An object. Each of its properties is either a * function or an array of requirements, with the {@link AsyncFunction} itself the last item * in the array. The object's key of a property serves as the name of the task * defined by that property, i.e. can be used when specifying requirements for * other tasks. The function receives one or two arguments: * * a `results` object, containing the results of the previously executed *   functions, only passed if the task has any dependencies, * * a `callback(err, result)` function, which must be called when finished, *   passing an `error` (which can be `null`) and the result of the function's *   execution. * @param {number} [concurrency=Infinity] - An optional `integer` for * determining the maximum number of tasks that can be run in parallel. By * default, as many as possible. * @param {Function} [callback] - An optional callback which is called when all * the tasks have been completed. It receives the `err` argument if any `tasks` * pass an error to their callback. Results are always returned; however, if an * error occurs, no further `tasks` will be performed, and the results object * will only contain partial results. Invoked with (err, results). * @returns {Promise} a promise, if a callback is not passed * @example * * //Using Callbacks * async.auto({ *     get_data: function(callback) { *         // async code to get some data *         callback(null, 'data', 'converted to array'); *     }, *     make_folder: function(callback) { *         // async code to create a directory to store a file in *         // this is run at the same time as getting the data *         callback(null, 'folder'); *     }, *     write_file: ['get_data', 'make_folder', function(results, callback) { *         // once there is some data and the directory exists, *         // write the data to a file in the directory *         callback(null, 'filename'); *     }], *     email_link: ['write_file', function(results, callback) { *         // once the file is written let's email a link to it... *         callback(null, {'file':results.write_file, 'email':'user@example.com'}); *     }] * }, function(err, results) { *     if (err) { *         console.log('err = ', err); *     } *     console.log('results = ', results); *     // results = { *     //     get_data: ['data', 'converted to array'] *     //     make_folder; 'folder', *     //     write_file: 'filename' *     //     email_link: { file: 'filename', email: 'user@example.com' } *     // } * }); * * //Using Promises * async.auto({ *     get_data: function(callback) { *         console.log('in get_data'); *         // async code to get some data *         callback(null, 'data', 'converted to array'); *     }, *     make_folder: function(callback) { *         console.log('in make_folder'); *         // async code to create a directory to store a file in *         // this is run at the same time as getting the data *         callback(null, 'folder'); *     }, *     write_file: ['get_data', 'make_folder', function(results, callback) { *         // once there is some data and the directory exists, *         // write the data to a file in the directory *         callback(null, 'filename'); *     }], *     email_link: ['write_file', function(results, callback) { *         // once the file is written let's email a link to it... *         callback(null, {'file':results.write_file, 'email':'user@example.com'}); *     }] * }).then(results => { *     console.log('results = ', results); *     // results = { *     //     get_data: ['data', 'converted to array'] *     //     make_folder; 'folder', *     //     write_file: 'filename' *     //     email_link: { file: 'filename', email: 'user@example.com' } *     // } * }).catch(err => { *     console.log('err = ', err); * }); * * //Using async/await * async () => { *     try { *         let results = await async.auto({ *             get_data: function(callback) { *                 // async code to get some data *                 callback(null, 'data', 'converted to array'); *             }, *             make_folder: function(callback) { *                 // async code to create a directory to store a file in *                 // this is run at the same time as getting the data *                 callback(null, 'folder'); *             }, *             write_file: ['get_data', 'make_folder', function(results, callback) { *                 // once there is some data and the directory exists, *                 // write the data to a file in the directory *                 callback(null, 'filename'); *             }], *             email_link: ['write_file', function(results, callback) { *                 // once the file is written let's email a link to it... *                 callback(null, {'file':results.write_file, 'email':'user@example.com'}); *             }] *         }); *         console.log('results = ', results); *         // results = { *         //     get_data: ['data', 'converted to array'] *         //     make_folder; 'folder', *         //     write_file: 'filename' *         //     email_link: { file: 'filename', email: 'user@example.com' } *         // } *     } *     catch (err) { *         console.log(err); *     } * } * */function auto(tasks, concurrency, callback) {    if (typeof concurrency !== 'number') {        // concurrency is optional, shift the args.        callback = concurrency;        concurrency = null;    }    callback = (0, _once2.default)(callback || (0, _promiseCallback.promiseCallback)());    var numTasks = Object.keys(tasks).length;    if (!numTasks) {        return callback(null);    }    if (!concurrency) {        concurrency = numTasks;    }    var results = {};    var runningTasks = 0;    var canceled = false;    var hasError = false;    var listeners = Object.create(null);    var readyTasks = [];    // for cycle detection:    var readyToCheck = []; // tasks that have been identified as reachable    // without the possibility of returning to an ancestor task    var uncheckedDependencies = {};    Object.keys(tasks).forEach(key => {        var task = tasks[key];        if (!Array.isArray(task)) {            // no dependencies            enqueueTask(key, [task]);            readyToCheck.push(key);            return;        }        var dependencies = task.slice(0, task.length - 1);        var remainingDependencies = dependencies.length;        if (remainingDependencies === 0) {            enqueueTask(key, task);            readyToCheck.push(key);            return;        }        uncheckedDependencies[key] = remainingDependencies;        dependencies.forEach(dependencyName => {            if (!tasks[dependencyName]) {                throw new Error('async.auto task `' + key + '` has a non-existent dependency `' + dependencyName + '` in ' + dependencies.join(', '));            }            addListener(dependencyName, () => {                remainingDependencies--;                if (remainingDependencies === 0) {                    enqueueTask(key, task);                }            });        });    });    checkForDeadlocks();    processQueue();    function enqueueTask(key, task) {        readyTasks.push(() => runTask(key, task));    }    function processQueue() {        if (canceled) return;        if (readyTasks.length === 0 && runningTasks === 0) {            return callback(null, results);        }        while (readyTasks.length && runningTasks < concurrency) {            var run = readyTasks.shift();            run();        }    }    function addListener(taskName, fn) {        var taskListeners = listeners[taskName];        if (!taskListeners) {            taskListeners = listeners[taskName] = [];        }        taskListeners.push(fn);    }    function taskComplete(taskName) {        var taskListeners = listeners[taskName] || [];        taskListeners.forEach(fn => fn());        processQueue();    }    function runTask(key, task) {        if (hasError) return;        var taskCallback = (0, _onlyOnce2.default)((err, ...result) => {            runningTasks--;            if (err === false) {                canceled = true;                return;            }            if (result.length < 2) {                [result] = result;            }            if (err) {                var safeResults = {};                Object.keys(results).forEach(rkey => {                    safeResults[rkey] = results[rkey];                });                safeResults[key] = result;                hasError = true;                listeners = Object.create(null);                if (canceled) return;                callback(err, safeResults);            } else {                results[key] = result;                taskComplete(key);            }        });        runningTasks++;        var taskFn = (0, _wrapAsync2.default)(task[task.length - 1]);        if (task.length > 1) {            taskFn(results, taskCallback);        } else {            taskFn(taskCallback);        }    }    function checkForDeadlocks() {        // Kahn's algorithm        // https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm        // http://connalle.blogspot.com/2013/10/topological-sortingkahn-algorithm.html        var currentTask;        var counter = 0;        while (readyToCheck.length) {            currentTask = readyToCheck.pop();            counter++;            getDependents(currentTask).forEach(dependent => {                if (--uncheckedDependencies[dependent] === 0) {                    readyToCheck.push(dependent);                }            });        }        if (counter !== numTasks) {            throw new Error('async.auto cannot execute tasks due to a recursive dependency');        }    }    function getDependents(taskName) {        var result = [];        Object.keys(tasks).forEach(key => {            const task = tasks[key];            if (Array.isArray(task) && task.indexOf(taskName) >= 0) {                result.push(key);            }        });        return result;    }    return callback[_promiseCallback.PROMISE_SYMBOL];}module.exports = exports.default;
 |