├── .travis.yml ├── example.js ├── .gitignore ├── LICENSE ├── package.json ├── bench.js ├── fall.js ├── test.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | 4 | node_js: 5 | - "0.10" 6 | - "0.12" 7 | - "iojs" 8 | - "4" 9 | - "5" 10 | 11 | cache: 12 | directories: 13 | - node_modules 14 | 15 | after_script: 16 | npm run coveralls -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var fall = require('./')() 4 | 5 | fall([ 6 | function a (cb) { 7 | console.log('called a') 8 | cb(null, 'a') 9 | }, 10 | function b (a, cb) { 11 | console.log('called b with:', a) 12 | cb(null, 'a', 'b') 13 | }, 14 | function c (a, b, cb) { 15 | console.log('called c with:', a, b) 16 | cb(null, 'a', 'b', 'c') 17 | } 18 | ], function result (err, a, b, c) { 19 | console.log('result arguments', err, a, b, c) 20 | }) 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matteo Collina 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastfall", 3 | "version": "1.5.1", 4 | "description": "call your callbacks in a waterfall, at speed", 5 | "main": "fall.js", 6 | "scripts": { 7 | "lint": "standard", 8 | "test": "tape test.js | faucet", 9 | "coverage": "istanbul cover tape test.js | tap-spec", 10 | "coveralls": "npm run coverage ; cat ./coverage/lcov.info | coveralls" 11 | }, 12 | "precommit": [ 13 | "lint", 14 | "test" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/mcollina/fastfall.git" 19 | }, 20 | "keywords": [ 21 | "async", 22 | "waterfall", 23 | "fall", 24 | "fast", 25 | "callback" 26 | ], 27 | "author": "Matteo Collina ", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/mcollina/fastfall/issues" 31 | }, 32 | "homepage": "https://github.com/mcollina/fastfall#readme", 33 | "engines": { 34 | "node": ">=0.10.0" 35 | }, 36 | "devDependencies": { 37 | "async": "^1.0.0", 38 | "coveralls": "^2.11.6", 39 | "fastbench": "^1.0.0", 40 | "faucet": "0.0.1", 41 | "insync": "^2.1.1", 42 | "istanbul": "^0.4.1", 43 | "neo-async": "^1.7.0", 44 | "pre-commit": "^1.0.10", 45 | "run-waterfall": "^1.1.1", 46 | "standard": "^5.0.0", 47 | "tap-spec": "^4.1.1", 48 | "tape": "^4.0.0", 49 | "waterfallize": "^1.0.0" 50 | }, 51 | "dependencies": { 52 | "reusify": "^1.0.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bench.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var max = 100000 4 | var async = require('async') 5 | var insync = require('insync') 6 | var neoAsync = require('neo-async') 7 | var fall = require('./')() 8 | var runWaterfall = require('run-waterfall') 9 | var waterfallize = require('waterfallize') 10 | var bench = require('fastbench') 11 | 12 | var nextDone 13 | var nextCount 14 | 15 | function benchSetImmediate (done) { 16 | nextCount = 3 17 | nextDone = done 18 | setImmediate(somethingImmediate) 19 | } 20 | 21 | function somethingImmediate () { 22 | nextCount-- 23 | if (nextCount === 0) { 24 | nextDone() 25 | } else { 26 | setImmediate(somethingImmediate) 27 | } 28 | } 29 | 30 | function somethingB (cb) { 31 | setImmediate(cb) 32 | } 33 | 34 | function somethingA (cb) { 35 | setImmediate(cb) 36 | } 37 | 38 | var toCall = [somethingA, somethingB, somethingB] 39 | function benchAsyncWaterfall (done) { 40 | async.waterfall(toCall, done) 41 | } 42 | 43 | function benchFastFall (done) { 44 | fall(toCall, done) 45 | } 46 | 47 | function benchWaterfallize (done) { 48 | var next = waterfallize() 49 | 50 | next(toCall[0]) 51 | next(toCall[1]) 52 | next(toCall[2]) 53 | next(done) 54 | } 55 | 56 | function benchRunWaterFall (done) { 57 | runWaterfall(toCall, done) 58 | } 59 | 60 | function benchInsync (done) { 61 | insync.waterfall(toCall, done) 62 | } 63 | 64 | function benchNeoAsync (done) { 65 | neoAsync.waterfall(toCall, done) 66 | } 67 | 68 | var compiled = require('./')(toCall) 69 | 70 | var run = bench([ 71 | benchAsyncWaterfall, 72 | benchInsync, 73 | benchNeoAsync, 74 | benchRunWaterFall, 75 | benchSetImmediate, 76 | benchWaterfallize, 77 | benchFastFall, 78 | compiled 79 | ], max) 80 | 81 | run(run) 82 | -------------------------------------------------------------------------------- /fall.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var reusify = require('reusify') 4 | var empty = [] 5 | 6 | function fastfall (context, template) { 7 | if (Array.isArray(context)) { 8 | template = context 9 | context = null 10 | } 11 | 12 | var queue = reusify(Holder) 13 | 14 | return template ? compiled : fall 15 | 16 | function fall () { 17 | var current = queue.get() 18 | current.release = release 19 | 20 | if (arguments.length === 3) { 21 | current.context = arguments[0] 22 | current.list = arguments[1] 23 | current.callback = arguments[2] || noop 24 | } else { 25 | current.context = context 26 | current.list = arguments[0] 27 | current.callback = arguments[1] || noop 28 | } 29 | 30 | current.work() 31 | } 32 | 33 | function release (holder) { 34 | queue.release(holder) 35 | } 36 | 37 | function compiled () { 38 | var current = queue.get() 39 | current.release = release 40 | 41 | current.list = template 42 | 43 | var args 44 | var i 45 | var len = arguments.length - 1 46 | 47 | current.context = this || context 48 | current.callback = arguments[len] || noop 49 | 50 | switch (len) { 51 | case 0: 52 | current.work() 53 | break 54 | case 1: 55 | current.work(null, arguments[0]) 56 | break 57 | case 2: 58 | current.work(null, arguments[0], arguments[1]) 59 | break 60 | case 3: 61 | current.work(null, arguments[0], arguments[1], arguments[2]) 62 | break 63 | case 4: 64 | current.work(null, arguments[0], arguments[1], arguments[2], arguments[3]) 65 | break 66 | default: 67 | args = new Array(len + 1) 68 | args[0] = null 69 | for (i = 0; i < len; i++) { 70 | args[i + 1] = arguments[i] 71 | } 72 | current.work.apply(null, args) 73 | } 74 | } 75 | } 76 | 77 | function noop () {} 78 | 79 | function Holder () { 80 | this.list = empty 81 | this.callback = noop 82 | this.count = 0 83 | this.context = undefined 84 | this.release = noop 85 | 86 | var that = this 87 | 88 | this.work = function work () { 89 | if (arguments.length > 0 && arguments[0]) { 90 | return that.callback.call(that.context, arguments[0]) 91 | } 92 | 93 | var len = arguments.length 94 | var i 95 | var args 96 | var func 97 | 98 | if (that.count < that.list.length) { 99 | func = that.list[that.count++] 100 | switch (len) { 101 | case 0: 102 | case 1: 103 | return func.call(that.context, work) 104 | case 2: 105 | return func.call(that.context, arguments[1], work) 106 | case 3: 107 | return func.call(that.context, arguments[1], arguments[2], work) 108 | case 4: 109 | return func.call(that.context, arguments[1], arguments[2], arguments[3], work) 110 | default: 111 | args = new Array(len) 112 | for (i = 1; i < len; i++) { 113 | args[i - 1] = arguments[i] 114 | } 115 | args[len - 1] = work 116 | func.apply(that.context, args) 117 | } 118 | } else { 119 | switch (len) { 120 | case 0: 121 | that.callback.call(that.context) 122 | break 123 | case 1: 124 | that.callback.call(that.context, arguments[0]) 125 | break 126 | case 2: 127 | that.callback.call(that.context, arguments[0], arguments[1]) 128 | break 129 | case 3: 130 | that.callback.call(that.context, arguments[0], arguments[1], arguments[2]) 131 | break 132 | case 4: 133 | that.callback.call(that.context, arguments[0], arguments[1], arguments[2], arguments[3]) 134 | break 135 | default: 136 | args = new Array(len) 137 | for (i = 0; i < len; i++) { 138 | args[i] = arguments[i] 139 | } 140 | that.callback.apply(that.context, args) 141 | } 142 | that.context = undefined 143 | that.list = empty 144 | that.count = 0 145 | that.release(that) 146 | } 147 | } 148 | } 149 | 150 | module.exports = fastfall 151 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var test = require('tape') 4 | var fastfall = require('./') 5 | 6 | test('basically works', function (t) { 7 | t.plan(22) 8 | 9 | var fall = fastfall() 10 | 11 | fall([ 12 | function a (cb) { 13 | cb(null, 'a') 14 | }, 15 | function b (a, cb) { 16 | t.equal(a, 'a', 'second function arg matches') 17 | cb(null, 'a', 'b') 18 | }, 19 | function c (a, b, cb) { 20 | t.equal(a, 'a', 'third function 1st arg matches') 21 | t.equal(b, 'b', 'third function 2nd arg matches') 22 | cb(null, 'a', 'b', 'c') 23 | }, 24 | function d (a, b, c, cb) { 25 | t.equal(a, 'a', 'fourth function 1st arg matches') 26 | t.equal(b, 'b', 'fourth function 2nd arg matches') 27 | t.equal(c, 'c', 'fourth function 3rd arg matches') 28 | cb(null, 'a', 'b', 'c', 'd') 29 | }, 30 | function e (a, b, c, d, cb) { 31 | t.equal(a, 'a', 'fifth function 1st arg matches') 32 | t.equal(b, 'b', 'fifth function 2nd arg matches') 33 | t.equal(c, 'c', 'fifth function 3rd arg matches') 34 | t.equal(d, 'd', 'fifth function 4th arg matches') 35 | cb(null, 'a', 'b', 'c', 'd', 'e') 36 | }, 37 | function f (a, b, c, d, e, cb) { 38 | t.equal(a, 'a', 'sixth function 1st arg matches') 39 | t.equal(b, 'b', 'sixth function 2nd arg matches') 40 | t.equal(c, 'c', 'sixth function 3rd arg matches') 41 | t.equal(d, 'd', 'sixth function 4th arg matches') 42 | t.equal(e, 'e', 'sixth function 5th arg matches') 43 | cb(null, 'a', 'b', 'c', 'd', 'e', 'f') 44 | } 45 | ], function result (err, a, b, c, d, e, f) { 46 | t.error(err, 'no error') 47 | t.equal(a, 'a', 'result function 2nd arg matches') 48 | t.equal(b, 'b', 'result function 3rd arg matches') 49 | t.equal(c, 'c', 'result function 4th arg matches') 50 | t.equal(d, 'd', 'result function 5th arg matches') 51 | t.equal(e, 'e', 'result function 6th arg matches') 52 | t.equal(f, 'f', 'result function 7th arg matches') 53 | }) 54 | }) 55 | 56 | test('call with error', function (t) { 57 | t.plan(4) 58 | 59 | var fall = fastfall() 60 | 61 | fall([ 62 | function a (cb) { 63 | cb(null, 'a') 64 | }, 65 | function b (a, cb) { 66 | t.equal(a, 'a', 'second function arg matches') 67 | cb(new Error('this is expected!'), 'a', 'b') 68 | }, 69 | function c (a, b, cb) { 70 | t.fail('this should never happen') 71 | } 72 | ], function result (err, a, b, c) { 73 | t.ok(err, 'error') 74 | t.notOk(a, 'no 2nd arg') 75 | t.notOk(b, 'no 3rd arg') 76 | }) 77 | }) 78 | 79 | test('compiles a reusable fall', function (t) { 80 | t.plan(10) 81 | 82 | var fall = fastfall([ 83 | function a (arg, cb) { 84 | cb(null, arg) 85 | }, 86 | function b (a, cb) { 87 | cb(null, a, 'b') 88 | }, 89 | function c (a, b, cb) { 90 | t.equal(b, 'b', 'third function 2nd arg matches') 91 | cb(null, a, 'b', 'c') 92 | } 93 | ]) 94 | 95 | fall(42, function result (err, a, b, c) { 96 | t.error(err, 'no error') 97 | t.equal(a, 42, 'result function 2nd arg matches') 98 | t.equal(b, 'b', 'result function 3rd arg matches') 99 | t.equal(c, 'c', 'result function 4th arg matches') 100 | }) 101 | 102 | fall(24, function result (err, a, b, c) { 103 | t.error(err, 'no error') 104 | t.equal(a, 24, 'result function 2nd arg matches') 105 | t.equal(b, 'b', 'result function 3rd arg matches') 106 | t.equal(c, 'c', 'result function 4th arg matches') 107 | }) 108 | }) 109 | 110 | test('set this', function (t) { 111 | t.plan(2) 112 | 113 | var that = {} 114 | var fall = fastfall(that) 115 | 116 | fall([ 117 | function a (cb) { 118 | t.equal(this, that, 'this is set') 119 | cb(null, 'a') 120 | } 121 | ], function result (err, a, b, c) { 122 | t.error(err, 'no error') 123 | }) 124 | }) 125 | 126 | test('set this in compiled mode', function (t) { 127 | t.plan(4) 128 | 129 | var that = {} 130 | var fall = fastfall(that, [ 131 | function a (arg, cb) { 132 | t.equal(this, that, 'this is set') 133 | cb(null, arg) 134 | } 135 | ]) 136 | 137 | fall(42, function result (err, a, b, c) { 138 | t.error(err, 'no error') 139 | t.equal(a, 42, 'result function 2nd arg matches') 140 | t.equal(this, that, 'this is set') 141 | }) 142 | }) 143 | 144 | test('set this for a normal fall', function (t) { 145 | t.plan(4) 146 | 147 | var that = {} 148 | var fall = fastfall() 149 | 150 | fall(that, [ 151 | function a (cb) { 152 | t.equal(this, that, 'this is set') 153 | cb(null, 'a') 154 | } 155 | ], function result (err, a) { 156 | t.error(err, 'no error') 157 | t.equal(this, that, 'this is set') 158 | t.equal(a, 'a', 'result function 2nd arg matches') 159 | }) 160 | }) 161 | 162 | test('use the this of the called object in compiled mode', function (t) { 163 | t.plan(4) 164 | 165 | var that = {} 166 | var fall = fastfall([ 167 | function a (arg, cb) { 168 | t.equal(this, that, 'this is set') 169 | cb(null, arg) 170 | } 171 | ]) 172 | 173 | fall.call(that, 42, function result (err, a, b, c) { 174 | t.error(err, 'no error') 175 | t.equal(a, 42, 'result function 2nd arg matches') 176 | t.equal(this, that, 'this is set') 177 | }) 178 | }) 179 | 180 | test('support errors in compiled mode', function (t) { 181 | t.plan(2) 182 | 183 | var fall = fastfall([ 184 | function a (arg, cb) { 185 | t.pass('function is called') 186 | cb(new Error('muahaha'), arg) 187 | } 188 | ]) 189 | 190 | fall(42, function result (err) { 191 | t.ok(err, 'error is forwarded') 192 | }) 193 | }) 194 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fastfall 2 | 3 | [![npm version][npm-badge]][npm-url] 4 | [![Build Status][travis-badge]][travis-url] 5 | [![Coverage Status][coveralls-badge]][coveralls-url] 6 | [![Dependency Status][david-badge]][david-url] 7 | 8 | ## call your callbacks in a waterfall, without overhead 9 | 10 | Benchmark for doing 3 calls `setImmediate` 100 thousands times: 11 | 12 | * non-reusable setImmediate: 407ms 13 | * [async.waterfall](https://github.com/caolan/async#waterfall): 1203ms 14 | * [run-waterfall](http://npm.im/run-waterfall): 1432ms 15 | * [insync.wasterfall](https://www.npmjs.com/package/insync#waterfall): 16 | 1570ms 17 | * [neo-async.wasterfall](http://suguru03.github.io/neo-async/doc/async.waterfall.html): 18 | 445ms 19 | * [waterfallize](http://npm.im/waterfallize): 757ms 20 | * `fastfall`: 432ms 21 | * `fastfall` compiled: 428ms 22 | 23 | 24 | These benchmarks where taken via `bench.js` on node 4.2.2, on a MacBook 25 | Pro Retina 2014 (i7, 16GB of RAM). 26 | 27 | If you need zero-overhead series function call, check out 28 | [fastseries](http://npm.im/fastseries), for parallel calls check out 29 | [fastparallel](http://npm.im/fastparallel), and for a fast work queue 30 | use [fastq](http://npm.im/fastq). 31 | 32 | [![js-standard-style](https://raw.githubusercontent.com/feross/standard/master/badge.png)](https://github.com/feross/standard) 33 | 34 | ## Install 35 | 36 | ``` 37 | npm install fastfall --save 38 | ``` 39 | 40 | ## Usage 41 | 42 | ```js 43 | var fall = require('fastfall')() 44 | 45 | fall([ 46 | function a (cb) { 47 | console.log('called a') 48 | cb(null, 'a') 49 | }, 50 | function b (a, cb) { 51 | console.log('called b with:', a) 52 | cb(null, 'a', 'b') 53 | }, 54 | function c (a, b, cb) { 55 | console.log('called c with:', a, b) 56 | cb(null, 'a', 'b', 'c') 57 | }], function result (err, a, b, c) { 58 | console.log('result arguments', arguments) 59 | }) 60 | ``` 61 | 62 | You can also set `this` when you create a fall: 63 | 64 | ```js 65 | var that = { hello: 'world' } 66 | var fall = require('fastfall')(that) 67 | 68 | fall([a, b, c], result) 69 | 70 | function a (cb) { 71 | console.log(this) 72 | console.log('called a') 73 | cb(null, 'a') 74 | } 75 | 76 | function b (a, cb) { 77 | console.log('called b with:', a) 78 | cb(null, 'a', 'b') 79 | } 80 | 81 | function c (a, b, cb) { 82 | console.log('called c with:', a, b) 83 | cb(null, 'a', 'b', 'c') 84 | } 85 | 86 | function result (err, a, b, c) { 87 | console.log('result arguments', arguments) 88 | } 89 | ``` 90 | 91 | You can also set `this` when you run a task: 92 | 93 | ```js 94 | var that = { hello: 'world' } 95 | var fall = require('fastfall')() 96 | 97 | fall(new State('world'), [ 98 | a, b, c, 99 | ], console.log) 100 | 101 | function State (value) { 102 | this.value = value 103 | } 104 | 105 | function a (cb) { 106 | console.log(this.value) 107 | console.log('called a') 108 | cb(null, 'a') 109 | } 110 | 111 | function b (a, cb) { 112 | console.log('called b with:', a) 113 | cb(null, 'a', 'b') 114 | } 115 | 116 | function c (a, b, cb) { 117 | console.log('called c with:', a, b) 118 | cb(null, 'a', 'b', 'c') 119 | } 120 | ``` 121 | 122 | ### Compile a waterfall 123 | 124 | ```js 125 | var fall = require('fastfall')([ 126 | function a (arg, cb) { 127 | console.log('called a') 128 | cb(null, arg) 129 | }, 130 | function b (a, cb) { 131 | console.log('called b with:', a) 132 | cb(null, 'a', 'b') 133 | }, 134 | function c (a, b, cb) { 135 | console.log('called c with:', a, b) 136 | cb(null, 'a', 'b', 'c') 137 | }]) 138 | 139 | // a compiled fall supports arguments too! 140 | fall(42, function result (err, a, b, c) { 141 | console.log('result arguments', arguments) 142 | }) 143 | ``` 144 | 145 | You can set `this` by doing: 146 | 147 | ```js 148 | var that = { hello: 'world' } 149 | var fall = require('fastfall')(that, [ 150 | function a (arg, cb) { 151 | console.log('this is', this) 152 | console.log('called a') 153 | cb(null, arg) 154 | }, 155 | function b (a, cb) { 156 | console.log('called b with:', a) 157 | cb(null, 'a', 'b') 158 | }, 159 | function c (a, b, cb) { 160 | console.log('called c with:', a, b) 161 | cb(null, 'a', 'b', 'c') 162 | }]) 163 | 164 | // a compiled fall supports arguments too! 165 | fall(42, function result (err, a, b, c) { 166 | console.log('result arguments', arguments) 167 | }) 168 | ``` 169 | 170 | or you can simply attach it to an object: 171 | 172 | ```js 173 | var that = { hello: 'world' } 174 | that.doSomething = require('fastfall')([ 175 | function a (arg, cb) { 176 | console.log('this is', this) 177 | console.log('called a') 178 | cb(null, arg) 179 | }, 180 | function b (a, cb) { 181 | console.log('called b with:', a) 182 | cb(null, 'a', 'b') 183 | }, 184 | function c (a, b, cb) { 185 | console.log('called c with:', a, b) 186 | cb(null, 'a', 'b', 'c') 187 | }]) 188 | 189 | // a compiled fall supports arguments too! 190 | that.doSomething(42, function result (err, a, b, c) { 191 | console.log('this is', this) 192 | console.log('result arguments', arguments) 193 | }) 194 | ``` 195 | 196 | ## API 197 | 198 | ### fastfall([this], [functions]) 199 | 200 | Creates a `fall`, it can either be pre-filled with a `this` value 201 | and an array of functions. 202 | 203 | If there is no list of functions, [a not-compiled fall](#not-compiled) 204 | is returned, if there is a list of function [a compiled fall](#compiled) 205 | is returned. 206 | 207 | 208 | ### fall([this], functions, [done]) 209 | 210 | Calls the functions in a waterfall, forwarding the arguments from one to 211 | another. Calls `done` when it has finished. 212 | 213 | 214 | ### fall(args..., [done]) 215 | 216 | Calls the compiled functions in a waterfall, forwarding the arguments from one to 217 | another. Additionally, a user can specify some arguments for the first 218 | function, too. Calls `done` when it has finished. 219 | 220 | ## License 221 | 222 | MIT 223 | 224 | 225 | [npm-badge]: https://badge.fury.io/js/fastfall.svg 226 | [npm-url]: https://badge.fury.io/js/fastfall 227 | [travis-badge]: https://api.travis-ci.org/mcollina/fastfall.svg 228 | [travis-url]: https://travis-ci.org/mcollina/fastfall 229 | [coveralls-badge]:https://coveralls.io/repos/mcollina/fastfall/badge.svg?branch=master&service=github 230 | [coveralls-url]: https://coveralls.io/github/mcollina/fastfall?branch=master 231 | [david-badge]: https://david-dm.org/mcollina/fastfall.svg 232 | [david-url]: https://david-dm.org/mcollina/fastfall 233 | --------------------------------------------------------------------------------