1'use strict'; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.default = ensureAsync; 7 8var _setImmediate = require('./internal/setImmediate.js'); 9 10var _setImmediate2 = _interopRequireDefault(_setImmediate); 11 12var _wrapAsync = require('./internal/wrapAsync.js'); 13 14function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 16/** 17 * Wrap an async function and ensure it calls its callback on a later tick of 18 * the event loop. If the function already calls its callback on a next tick, 19 * no extra deferral is added. This is useful for preventing stack overflows 20 * (`RangeError: Maximum call stack size exceeded`) and generally keeping 21 * [Zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony) 22 * contained. ES2017 `async` functions are returned as-is -- they are immune 23 * to Zalgo's corrupting influences, as they always resolve on a later tick. 24 * 25 * @name ensureAsync 26 * @static 27 * @memberOf module:Utils 28 * @method 29 * @category Util 30 * @param {AsyncFunction} fn - an async function, one that expects a node-style 31 * callback as its last argument. 32 * @returns {AsyncFunction} Returns a wrapped function with the exact same call 33 * signature as the function passed in. 34 * @example 35 * 36 * function sometimesAsync(arg, callback) { 37 * if (cache[arg]) { 38 * return callback(null, cache[arg]); // this would be synchronous!! 39 * } else { 40 * doSomeIO(arg, callback); // this IO would be asynchronous 41 * } 42 * } 43 * 44 * // this has a risk of stack overflows if many results are cached in a row 45 * async.mapSeries(args, sometimesAsync, done); 46 * 47 * // this will defer sometimesAsync's callback if necessary, 48 * // preventing stack overflows 49 * async.mapSeries(args, async.ensureAsync(sometimesAsync), done); 50 */ 51function ensureAsync(fn) { 52 if ((0, _wrapAsync.isAsync)(fn)) return fn; 53 return function (...args /*, callback*/) { 54 var callback = args.pop(); 55 var sync = true; 56 args.push((...innerArgs) => { 57 if (sync) { 58 (0, _setImmediate2.default)(() => callback(...innerArgs)); 59 } else { 60 callback(...innerArgs); 61 } 62 }); 63 fn.apply(this, args); 64 sync = false; 65 }; 66} 67module.exports = exports['default'];