funseq_async.js (3133B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var isFunction = require( '@stdlib/assert/is-function' ); 24 25 26 // MAIN // 27 28 /** 29 * Function sequence. 30 * 31 * @param {...Function} f - functions to evaluate in sequential order 32 * @throws {Error} must provide more than one argument 33 * @throws {TypeError} must provide functions 34 * @returns {Function} pipeline function 35 * 36 * @example 37 * function a( x, next ) { 38 * setTimeout( onTimeout, 0 ); 39 * function onTimeout() { 40 * next( null, 2*x ); 41 * } 42 * } 43 * 44 * function b( x, next ) { 45 * setTimeout( onTimeout, 0 ); 46 * function onTimeout() { 47 * next( null, x+3 ); 48 * } 49 * } 50 * 51 * function c( x, next ) { 52 * setTimeout( onTimeout, 0 ); 53 * function onTimeout() { 54 * next( null, x/5 ); 55 * } 56 * } 57 * 58 * var f = funseqAsync( a, b, c ); 59 * 60 * function done( error, result ) { 61 * if ( error ) { 62 * throw error; 63 * } 64 * console.log( result ); 65 * // => 3 66 * } 67 * 68 * f( 6, done ); 69 */ 70 function funseqAsync() { 71 var nFuncs; 72 var f; 73 var i; 74 nFuncs = arguments.length; 75 if ( nFuncs < 2 ) { 76 throw new Error( 'insufficient input arguments. Must provide multiple functions to execute sequentially.' ); 77 } 78 f = new Array( nFuncs ); 79 for ( i = 0; i < nFuncs; i++ ) { 80 f[ i ] = arguments[ i ]; 81 if ( !isFunction( f[ i ] ) ) { 82 throw new TypeError( 'invalid argument. All arguments must be functions. Value: `'+f[ i ]+'`.' ); 83 } 84 } 85 return pipeline; 86 87 /** 88 * Pipeline function. 89 * 90 * @private 91 * @param {...*} args - arguments 92 * @param {Callback} done - callback to invoke after invoking all functions 93 */ 94 function pipeline() { 95 var done; 96 var args; 97 var i; 98 99 // Cache the callback function: 100 done = arguments[ arguments.length-1 ]; 101 102 // Copy arguments which should be provided to the first invoked function... 103 args = new Array( arguments.length-1 ); 104 for ( i = 0; i < args.length; i++ ) { 105 args[ i ] = arguments[ i ]; 106 } 107 // Append the callback an invoked function should call upon completion: 108 args.push( next ); 109 110 // Start invoking provided functions: 111 i = 0; 112 f[ i ].apply( null, args ); 113 114 /** 115 * Callback invoked upon completion of a provided function. 116 * 117 * @private 118 * @param {(Error|null)} error - error object 119 * @param {*} result - result to pass to next function 120 * @returns {void} 121 */ 122 function next( error, result ) { 123 if ( error ) { 124 return done( error ); 125 } 126 i += 1; 127 if ( i === nFuncs ) { 128 return done( null, result ); 129 } 130 f[ i ]( result, next ); 131 } 132 } 133 } 134 135 136 // EXPORTS // 137 138 module.exports = funseqAsync;