wrapSync.js
1 'use strict'; 2 3 Object.defineProperty(exports, "__esModule", { 4 value: true 5 }); 6 exports.default = asyncify; 7 8 var _initialParams = require('./internal/initialParams'); 9 10 var _initialParams2 = _interopRequireDefault(_initialParams); 11 12 var _setImmediate = require('./internal/setImmediate'); 13 14 var _setImmediate2 = _interopRequireDefault(_setImmediate); 15 16 var _wrapAsync = require('./internal/wrapAsync'); 17 18 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 19 20 /** 21 * Take a sync function and make it async, passing its return value to a 22 * callback. This is useful for plugging sync functions into a waterfall, 23 * series, or other async functions. Any arguments passed to the generated 24 * function will be passed to the wrapped function (except for the final 25 * callback argument). Errors thrown will be passed to the callback. 26 * 27 * If the function passed to `asyncify` returns a Promise, that promises's 28 * resolved/rejected state will be used to call the callback, rather than simply 29 * the synchronous return value. 30 * 31 * This also means you can asyncify ES2017 `async` functions. 32 * 33 * @name asyncify 34 * @static 35 * @memberOf module:Utils 36 * @method 37 * @alias wrapSync 38 * @category Util 39 * @param {Function} func - The synchronous function, or Promise-returning 40 * function to convert to an {@link AsyncFunction}. 41 * @returns {AsyncFunction} An asynchronous wrapper of the `func`. To be 42 * invoked with `(args..., callback)`. 43 * @example 44 * 45 * // passing a regular synchronous function 46 * async.waterfall([ 47 * async.apply(fs.readFile, filename, "utf8"), 48 * async.asyncify(JSON.parse), 49 * function (data, next) { 50 * // data is the result of parsing the text. 51 * // If there was a parsing error, it would have been caught. 52 * } 53 * ], callback); 54 * 55 * // passing a function returning a promise 56 * async.waterfall([ 57 * async.apply(fs.readFile, filename, "utf8"), 58 * async.asyncify(function (contents) { 59 * return db.model.create(contents); 60 * }), 61 * function (model, next) { 62 * // `model` is the instantiated model object. 63 * // If there was an error, this function would be skipped. 64 * } 65 * ], callback); 66 * 67 * // es2017 example, though `asyncify` is not needed if your JS environment 68 * // supports async functions out of the box 69 * var q = async.queue(async.asyncify(async function(file) { 70 * var intermediateStep = await processFile(file); 71 * return await somePromise(intermediateStep) 72 * })); 73 * 74 * q.push(files); 75 */ 76 function asyncify(func) { 77 if ((0, _wrapAsync.isAsync)(func)) { 78 return function (...args /*, callback*/) { 79 const callback = args.pop(); 80 const promise = func.apply(this, args); 81 return handlePromise(promise, callback); 82 }; 83 } 84 85 return (0, _initialParams2.default)(function (args, callback) { 86 var result; 87 try { 88 result = func.apply(this, args); 89 } catch (e) { 90 return callback(e); 91 } 92 // if result is Promise object 93 if (result && typeof result.then === 'function') { 94 return handlePromise(result, callback); 95 } else { 96 callback(null, result); 97 } 98 }); 99 } 100 101 function handlePromise(promise, callback) { 102 return promise.then(value => { 103 invokeCallback(callback, null, value); 104 }, err => { 105 invokeCallback(callback, err && err.message ? err : new Error(err)); 106 }); 107 } 108 109 function invokeCallback(callback, error, value) { 110 try { 111 callback(error, value); 112 } catch (err) { 113 (0, _setImmediate2.default)(e => { 114 throw e; 115 }, err); 116 } 117 } 118 module.exports = exports['default'];