├── .circleci └── config.yml ├── .gitignore ├── .jsbeautifyrc ├── .jscsrc ├── .jsdocrc ├── .jshintrc ├── .prettierignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── bower.json ├── dist ├── async.js └── async.min.js ├── gulp ├── .eslintrc ├── .jshintrc ├── config.js ├── tasks │ ├── gh-pages.js │ ├── jscs.js │ ├── jsdoc.js │ ├── minify.js │ ├── npm.js │ ├── release.js │ └── test.js ├── template └── util.js ├── gulpfile.js ├── lib ├── async.js └── async.min.js ├── package-lock.json ├── package.json ├── perf ├── README.md ├── benchmark │ └── index.js ├── config.js ├── func-comparator │ └── index.js └── index.js └── test ├── collections ├── test.concat.js ├── test.detect.js ├── test.each.js ├── test.every.js ├── test.filter.js ├── test.groupBy.js ├── test.map.js ├── test.mapValues.js ├── test.omit.js ├── test.pick.js ├── test.reduce.js ├── test.reject.js ├── test.some.js ├── test.sortBy.js └── test.transform.js ├── config.js ├── controlFlow ├── test.angelFall.js ├── test.apply.js ├── test.applyEach.js ├── test.auto.js ├── test.autoInject.js ├── test.cargo.js ├── test.compose.js ├── test.during.js ├── test.forever.js ├── test.iterator.js ├── test.parallel.js ├── test.queue.js ├── test.race.js ├── test.retry.js ├── test.retryable.js ├── test.seq.js ├── test.series.js ├── test.timeout.js ├── test.times.js ├── test.tryEach.js ├── test.until.js ├── test.waterfall.js └── test.whilst.js ├── mocha.opts ├── other ├── test.alias.js └── test.other.js ├── util.js └── utils ├── test.asyncify.js ├── test.constant.js ├── test.createLogger.js ├── test.ensureAsync.js ├── test.memoize.js ├── test.reflect.js └── test.unmemoize.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | 2 | # Javascript Node CircleCI 2.0 configuration file 3 | # 4 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 5 | # 6 | version: 2 7 | jobs: 8 | build: 9 | docker: 10 | # specify the version you desire here 11 | - image: circleci/node:10 12 | 13 | working_directory: ~/repo 14 | 15 | steps: 16 | - checkout 17 | 18 | # Download and cache dependencies 19 | - restore_cache: 20 | keys: 21 | - v1-dependencies-{{ checksum "package.json" }} 22 | # fallback to using the latest cache if no exact match is found 23 | - v1-dependencies- 24 | 25 | - run: npm install 26 | 27 | - save_cache: 28 | paths: 29 | - node_modules 30 | key: v1-dependencies-{{ checksum "package.json" }} 31 | 32 | # run tests! 33 | - run: 34 | name: Test 35 | command: npm test 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | coverage 4 | doc 5 | build 6 | compiler.jar 7 | 8 | .idea 9 | -------------------------------------------------------------------------------- /.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "indent_size": 2, 3 | "indent_char": " ", 4 | "eol": "\n", 5 | "indent_level": 0, 6 | "indent_with_tabs": false, 7 | "preserve_newlines": true, 8 | "max_preserve_newlines": 2, 9 | "jslint_happy": false, 10 | "space_after_anon_function": false, 11 | "brace_style": "collapse", 12 | "keep_array_indentation": true, 13 | "keep_function_indentation": false, 14 | "space_before_conditional": true, 15 | "break_chained_methods": false, 16 | "eval_code": false, 17 | "unescape_strings": false, 18 | "wrap_line_length": 0, 19 | "wrap_attributes": "auto", 20 | "wrap_attributes_indent_size": 2, 21 | "end_with_newline": true 22 | } 23 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "disallowKeywords": ["with"], 3 | "disallowMixedSpacesAndTabs": true, 4 | "disallowMultipleLineStrings": true, 5 | "disallowNewlineBeforeBlockStatements": true, 6 | "disallowSpaceAfterObjectKeys": true, 7 | "disallowSpaceAfterPrefixUnaryOperators": ["!"], 8 | "disallowSpaceBeforeBinaryOperators": [","], 9 | "disallowSpacesInAnonymousFunctionExpression": { 10 | "beforeOpeningRoundBrace": true 11 | }, 12 | "disallowSpacesInFunctionDeclaration": { 13 | "beforeOpeningRoundBrace": true 14 | }, 15 | "disallowSpacesInNamedFunctionExpression": { 16 | "beforeOpeningRoundBrace": true 17 | }, 18 | "disallowSpacesInsideParentheses": true, 19 | "disallowTrailingComma": true, 20 | "disallowTrailingWhitespace": true, 21 | "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], 22 | "requireSpacesInFunction": { 23 | "beforeOpeningCurlyBrace": true 24 | }, 25 | "validateParameterSeparator": ", ", 26 | "requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"], 27 | "requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"], 28 | "requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"], 29 | "disallowImplicitTypeConversion": ["string"], 30 | "disallowMultipleLineBreaks": true, 31 | "disallowKeywordsOnNewLine": ["else"], 32 | "requireLineFeedAtFileEnd": true 33 | } 34 | -------------------------------------------------------------------------------- /.jsdocrc: -------------------------------------------------------------------------------- 1 | { 2 | "opts": { 3 | "destination": "./doc", 4 | "recurse": true 5 | }, 6 | "source": { 7 | "includePattern": ".+\\.js(doc)?$", 8 | "excludePattern": "(coverage/)|(doc/)|(node_modules/)" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "predef": [ 4 | "define", 5 | "Symbol" 6 | ], 7 | 8 | "indent": 2, 9 | 10 | "bitwise": false, 11 | "camelcase": false, 12 | "curly": false, 13 | "eqeqeq": true, 14 | "forin": false, 15 | "immed": true, 16 | "latedef": false, 17 | "newcap": false, 18 | "noarg": true, 19 | "noempty": false, 20 | "nonew": false, 21 | "plusplus": false, 22 | "quotmark": false, 23 | "regexp": false, 24 | "undef": true, 25 | "unused": true, 26 | "strict": true, 27 | "trailing": true, 28 | "maxparams": false, 29 | "maxdepth": false, 30 | "maxstatements": false, 31 | "maxcomplexity": false, 32 | "maxlen": false, 33 | 34 | "boss": false, 35 | "debug": false, 36 | "eqnull": true, 37 | "esnext": true, 38 | "evil": true, 39 | "expr": true, 40 | "funcscope": false, 41 | "globalstrict": false, 42 | "lastsemic": false, 43 | "laxbreak": false, 44 | "laxcomma": true, 45 | "loopfunc": false, 46 | "multistr": false, 47 | "onecase": false, 48 | "proto": true, 49 | "regexdash": false, 50 | "scripturl": true, 51 | "smarttabs": false, 52 | "shadow": false, 53 | "sub": false, 54 | "supernew": false, 55 | "validthis": false, 56 | 57 | "browser": true, 58 | "jquery": true, 59 | "node": true, 60 | "worker": true, 61 | 62 | "nomen": false, 63 | "onevar": false, 64 | "white": false, 65 | 66 | "-W018": true, 67 | 68 | "es3":true 69 | } 70 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | arch: 2 | - amd64 3 | - ppc64le 4 | language: node_js 5 | 6 | after_success: 'make test-codecov; make clean' 7 | 8 | install: npm install 9 | 10 | node_js: 11 | - 'node' 12 | - '12' 13 | - '10' 14 | - '8' 15 | - '6' 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-2018 Suguru Motegi 4 | Based on Async.js, Copyright Caolan McMahon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MOCHA=./node_modules/mocha/bin/_mocha 2 | ISTANBUL=./node_modules/.bin/istanbul 3 | 4 | test-cov: clean 5 | $(ISTANBUL) cover $(MOCHA) --report lcovonly -- -R spec ./test/*/*.js 6 | 7 | test-codecov: 8 | cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js --verbose 9 | 10 | release-test: 11 | DELAY=20 npm test | npm run-script cov:100 12 | 13 | clean: 14 | rm -rf coverage 15 | 16 | minify: 17 | java -jar ../compiler-latest/compiler.jar --js ./lib/async.js --js_output_file ./lib/async.min.js 18 | 19 | cp: 20 | cp ./lib/async.min.js ./dist/async.min.js 21 | cp ./lib/async.js ./dist/async.js 22 | 23 | release: release-test minify cp 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Neo-Async

2 | 3 |

4 | 5 |

6 | 7 |

8 | npm 9 | Travis Status 10 | Coverage Status 11 | download 12 | Code Quality: Javascript 13 | Total Alerts 14 | FOSSA 15 |

16 | 17 | Neo-Async is thought to be used as a drop-in replacement for [Async](https://github.com/caolan/async), it almost fully covers its functionality and runs [faster](#benchmark). 18 | 19 | Benchmark is [here](#benchmark)! 20 | 21 | Bluebird's benchmark is [here](https://github.com/suguru03/bluebird/tree/aigle/benchmark)! 22 | 23 | ## Code Coverage 24 | ![coverage](https://raw.githubusercontent.com/wiki/suguru03/neo-async/images/coverage.png) 25 | 26 | ## Installation 27 | 28 | ### In a browser 29 | ```html 30 | 31 | ``` 32 | 33 | ### In an AMD loader 34 | ```js 35 | require(['async'], function(async) {}); 36 | ``` 37 | 38 | ### Promise and async/await 39 | 40 | I recommend to use [`Aigle`](https://github.com/suguru03/aigle). 41 | 42 | It is optimized for Promise handling and has almost the same functionality as `neo-async`. 43 | 44 | ### Node.js 45 | 46 | #### standard 47 | 48 | ```bash 49 | $ npm install neo-async 50 | ``` 51 | ```js 52 | var async = require('neo-async'); 53 | ``` 54 | 55 | #### replacement 56 | ```bash 57 | $ npm install neo-async 58 | $ ln -s ./node_modules/neo-async ./node_modules/async 59 | ``` 60 | ```js 61 | var async = require('async'); 62 | ``` 63 | 64 | ### Bower 65 | 66 | ```bash 67 | bower install neo-async 68 | ``` 69 | 70 | ## Feature 71 | 72 | [JSDoc](http://suguru03.github.io/neo-async/doc/async.html) 73 | 74 | \* not in Async 75 | 76 | ### Collections 77 | 78 | - [`each`](http://suguru03.github.io/neo-async/doc/async.each.html) 79 | - [`eachSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) 80 | - [`eachLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) 81 | - [`forEach`](http://suguru03.github.io/neo-async/doc/async.each.html) -> [`each`](http://suguru03.github.io/neo-async/doc/async.each.html) 82 | - [`forEachSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) -> [`eachSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) 83 | - [`forEachLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) -> [`eachLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) 84 | - [`eachOf`](http://suguru03.github.io/neo-async/doc/async.each.html) -> [`each`](http://suguru03.github.io/neo-async/doc/async.each.html) 85 | - [`eachOfSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) -> [`eachSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) 86 | - [`eachOfLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) -> [`eachLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) 87 | - [`forEachOf`](http://suguru03.github.io/neo-async/doc/async.each.html) -> [`each`](http://suguru03.github.io/neo-async/doc/async.each.html) 88 | - [`forEachOfSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) -> [`eachSeries`](http://suguru03.github.io/neo-async/doc/async.eachSeries.html) 89 | - [`eachOfLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) -> [`forEachLimit`](http://suguru03.github.io/neo-async/doc/async.eachLimit.html) 90 | - [`map`](http://suguru03.github.io/neo-async/doc/async.map.html) 91 | - [`mapSeries`](http://suguru03.github.io/neo-async/doc/async.mapSeries.html) 92 | - [`mapLimit`](http://suguru03.github.io/neo-async/doc/async.mapLimit.html) 93 | - [`mapValues`](http://suguru03.github.io/neo-async/doc/async.mapValues.html) 94 | - [`mapValuesSeries`](http://suguru03.github.io/neo-async/doc/async.mapValuesSeries.html) 95 | - [`mapValuesLimit`](http://suguru03.github.io/neo-async/doc/async.mapValuesLimit.html) 96 | - [`filter`](http://suguru03.github.io/neo-async/doc/async.filter.html) 97 | - [`filterSeries`](http://suguru03.github.io/neo-async/doc/async.filterSeries.html) 98 | - [`filterLimit`](http://suguru03.github.io/neo-async/doc/async.filterLimit.html) 99 | - [`select`](http://suguru03.github.io/neo-async/doc/async.filter.html) -> [`filter`](http://suguru03.github.io/neo-async/doc/async.filter.html) 100 | - [`selectSeries`](http://suguru03.github.io/neo-async/doc/async.filterSeries.html) -> [`filterSeries`](http://suguru03.github.io/neo-async/doc/async.filterSeries.html) 101 | - [`selectLimit`](http://suguru03.github.io/neo-async/doc/async.filterLimit.html) -> [`filterLimit`](http://suguru03.github.io/neo-async/doc/async.filterLimit.html) 102 | - [`reject`](http://suguru03.github.io/neo-async/doc/async.reject.html) 103 | - [`rejectSeries`](http://suguru03.github.io/neo-async/doc/async.rejectSeries.html) 104 | - [`rejectLimit`](http://suguru03.github.io/neo-async/doc/async.rejectLimit.html) 105 | - [`detect`](http://suguru03.github.io/neo-async/doc/async.detect.html) 106 | - [`detectSeries`](http://suguru03.github.io/neo-async/doc/async.detectSeries.html) 107 | - [`detectLimit`](http://suguru03.github.io/neo-async/doc/async.detectLimit.html) 108 | - [`find`](http://suguru03.github.io/neo-async/doc/async.detect.html) -> [`detect`](http://suguru03.github.io/neo-async/doc/async.detect.html) 109 | - [`findSeries`](http://suguru03.github.io/neo-async/doc/async.detectSeries.html) -> [`detectSeries`](http://suguru03.github.io/neo-async/doc/async.detectSeries.html) 110 | - [`findLimit`](http://suguru03.github.io/neo-async/doc/async.detectLimit.html) -> [`detectLimit`](http://suguru03.github.io/neo-async/doc/async.detectLimit.html) 111 | - [`pick`](http://suguru03.github.io/neo-async/doc/async.pick.html) * 112 | - [`pickSeries`](http://suguru03.github.io/neo-async/doc/async.pickSeries.html) * 113 | - [`pickLimit`](http://suguru03.github.io/neo-async/doc/async.pickLimit.html) * 114 | - [`omit`](http://suguru03.github.io/neo-async/doc/async.omit.html) * 115 | - [`omitSeries`](http://suguru03.github.io/neo-async/doc/async.omitSeries.html) * 116 | - [`omitLimit`](http://suguru03.github.io/neo-async/doc/async.omitLimit.html) * 117 | - [`reduce`](http://suguru03.github.io/neo-async/doc/async.reduce.html) 118 | - [`inject`](http://suguru03.github.io/neo-async/doc/async.reduce.html) -> [`reduce`](http://suguru03.github.io/neo-async/doc/async.reduce.html) 119 | - [`foldl`](http://suguru03.github.io/neo-async/doc/async.reduce.html) -> [`reduce`](http://suguru03.github.io/neo-async/doc/async.reduce.html) 120 | - [`reduceRight`](http://suguru03.github.io/neo-async/doc/async.reduceRight.html) 121 | - [`foldr`](http://suguru03.github.io/neo-async/doc/async.reduceRight.html) -> [`reduceRight`](http://suguru03.github.io/neo-async/doc/async.reduceRight.html) 122 | - [`transform`](http://suguru03.github.io/neo-async/doc/async.transform.html) 123 | - [`transformSeries`](http://suguru03.github.io/neo-async/doc/async.transformSeries.html) * 124 | - [`transformLimit`](http://suguru03.github.io/neo-async/doc/async.transformLimit.html) * 125 | - [`sortBy`](http://suguru03.github.io/neo-async/doc/async.sortBy.html) 126 | - [`sortBySeries`](http://suguru03.github.io/neo-async/doc/async.sortBySeries.html) * 127 | - [`sortByLimit`](http://suguru03.github.io/neo-async/doc/async.sortByLimit.html) * 128 | - [`some`](http://suguru03.github.io/neo-async/doc/async.some.html) 129 | - [`someSeries`](http://suguru03.github.io/neo-async/doc/async.someSeries.html) 130 | - [`someLimit`](http://suguru03.github.io/neo-async/doc/async.someLimit.html) 131 | - [`any`](http://suguru03.github.io/neo-async/doc/async.some.html) -> [`some`](http://suguru03.github.io/neo-async/doc/async.some.html) 132 | - [`anySeries`](http://suguru03.github.io/neo-async/doc/async.someSeries.html) -> [`someSeries`](http://suguru03.github.io/neo-async/doc/async.someSeries.html) 133 | - [`anyLimit`](http://suguru03.github.io/neo-async/doc/async.someLimit.html) -> [`someLimit`](http://suguru03.github.io/neo-async/doc/async.someLimit.html) 134 | - [`every`](http://suguru03.github.io/neo-async/doc/async.every.html) 135 | - [`everySeries`](http://suguru03.github.io/neo-async/doc/async.everySeries.html) 136 | - [`everyLimit`](http://suguru03.github.io/neo-async/doc/async.everyLimit.html) 137 | - [`all`](http://suguru03.github.io/neo-async/doc/async.every.html) -> [`every`](http://suguru03.github.io/neo-async/doc/async.every.html) 138 | - [`allSeries`](http://suguru03.github.io/neo-async/doc/async.everySeries.html) -> [`every`](http://suguru03.github.io/neo-async/doc/async.everySeries.html) 139 | - [`allLimit`](http://suguru03.github.io/neo-async/doc/async.everyLimit.html) -> [`every`](http://suguru03.github.io/neo-async/doc/async.everyLimit.html) 140 | - [`concat`](http://suguru03.github.io/neo-async/doc/async.concat.html) 141 | - [`concatSeries`](http://suguru03.github.io/neo-async/doc/async.concatSeries.html) 142 | - [`concatLimit`](http://suguru03.github.io/neo-async/doc/async.concatLimit.html) * 143 | 144 | ### Control Flow 145 | 146 | - [`parallel`](http://suguru03.github.io/neo-async/doc/async.parallel.html) 147 | - [`series`](http://suguru03.github.io/neo-async/doc/async.series.html) 148 | - [`parallelLimit`](http://suguru03.github.io/neo-async/doc/async.parallelLimit.html) 149 | - [`tryEach`](http://suguru03.github.io/neo-async/doc/async.tryEach.html) 150 | - [`waterfall`](http://suguru03.github.io/neo-async/doc/async.waterfall.html) 151 | - [`angelFall`](http://suguru03.github.io/neo-async/doc/async.angelFall.html) * 152 | - [`angelfall`](http://suguru03.github.io/neo-async/doc/async.angelFall.html) -> [`angelFall`](http://suguru03.github.io/neo-async/doc/async.angelFall.html) * 153 | - [`whilst`](#whilst) 154 | - [`doWhilst`](#doWhilst) 155 | - [`until`](#until) 156 | - [`doUntil`](#doUntil) 157 | - [`during`](#during) 158 | - [`doDuring`](#doDuring) 159 | - [`forever`](#forever) 160 | - [`compose`](#compose) 161 | - [`seq`](#seq) 162 | - [`applyEach`](#applyEach) 163 | - [`applyEachSeries`](#applyEachSeries) 164 | - [`queue`](#queue) 165 | - [`priorityQueue`](#priorityQueue) 166 | - [`cargo`](#cargo) 167 | - [`auto`](#auto) 168 | - [`autoInject`](#autoInject) 169 | - [`retry`](#retry) 170 | - [`retryable`](#retryable) 171 | - [`iterator`](#iterator) 172 | - [`times`](http://suguru03.github.io/neo-async/doc/async.times.html) 173 | - [`timesSeries`](http://suguru03.github.io/neo-async/doc/async.timesSeries.html) 174 | - [`timesLimit`](http://suguru03.github.io/neo-async/doc/async.timesLimit.html) 175 | - [`race`](#race) 176 | 177 | ### Utils 178 | - [`apply`](#apply) 179 | - [`setImmediate`](#setImmediate) 180 | - [`nextTick`](#nextTick) 181 | - [`memoize`](#memoize) 182 | - [`unmemoize`](#unmemoize) 183 | - [`ensureAsync`](#ensureAsync) 184 | - [`constant`](#constant) 185 | - [`asyncify`](#asyncify) 186 | - [`wrapSync`](#asyncify) -> [`asyncify`](#asyncify) 187 | - [`log`](#log) 188 | - [`dir`](#dir) 189 | - [`timeout`](http://suguru03.github.io/neo-async/doc/async.timeout.html) 190 | - [`reflect`](#reflect) 191 | - [`reflectAll`](#reflectAll) 192 | - [`createLogger`](#createLogger) 193 | 194 | ## Mode 195 | - [`safe`](#safe) * 196 | - [`fast`](#fast) * 197 | 198 | ## Benchmark 199 | 200 | [Benchmark: Async vs Neo-Async](http://suguru03.hatenablog.com/entry/2016/06/10/135559) 201 | 202 | ### How to check 203 | 204 | ```bash 205 | $ node perf 206 | ``` 207 | 208 | ### Environment 209 | 210 | * Darwin 17.3.0 x64 211 | * Node.js v8.9.4 212 | * async v2.6.0 213 | * neo-async v2.5.0 214 | * benchmark v2.1.4 215 | 216 | ### Result 217 | 218 | The value is the ratio (Neo-Async/Async) of the average speed. 219 | 220 | #### Collections 221 | |function|benchmark| 222 | |---|--:| 223 | |each/forEach|2.43| 224 | |eachSeries/forEachSeries|1.75| 225 | |eachLimit/forEachLimit|1.68| 226 | |eachOf|3.29| 227 | |eachOfSeries|1.50| 228 | |eachOfLimit|1.59| 229 | |map|3.95| 230 | |mapSeries|1.81| 231 | |mapLimit|1.27| 232 | |mapValues|2.73| 233 | |mapValuesSeries|1.59| 234 | |mapValuesLimit|1.23| 235 | |filter|3.00| 236 | |filterSeries|1.74| 237 | |filterLimit|1.17| 238 | |reject|4.59| 239 | |rejectSeries|2.31| 240 | |rejectLimit|1.58| 241 | |detect|4.30| 242 | |detectSeries|1.86| 243 | |detectLimit|1.32| 244 | |reduce|1.82| 245 | |transform|2.46| 246 | |sortBy|4.08| 247 | |some|2.19| 248 | |someSeries|1.83| 249 | |someLimit|1.32| 250 | |every|2.09| 251 | |everySeries|1.84| 252 | |everyLimit|1.35| 253 | |concat|3.79| 254 | |concatSeries|4.45| 255 | 256 | #### Control Flow 257 | |funciton|benchmark| 258 | |---|--:| 259 | |parallel|2.93| 260 | |series|1.96| 261 | |waterfall|1.29| 262 | |whilst|1.00| 263 | |doWhilst|1.12| 264 | |until|1.12| 265 | |doUntil|1.12| 266 | |during|1.18| 267 | |doDuring|2.42| 268 | |times|4.25| 269 | |auto|1.97| 270 | 271 | 272 | ## License 273 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsuguru03%2Fneo-async.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsuguru03%2Fneo-async?ref=badge_large) 274 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neo-async", 3 | "main": "lib/async.js", 4 | "version": "2.6.2", 5 | "homepage": "https://github.com/suguru03/neo-async", 6 | "authors": [ 7 | "Suguru Motegi" 8 | ], 9 | "description": "Neo-Async is thought to be used as a drop-in replacement for Async, it almost fully covers its functionality and runs faster ", 10 | "moduleType": [ 11 | "amd", 12 | "globals", 13 | "node" 14 | ], 15 | "keywords": [ 16 | "async", 17 | "util" 18 | ], 19 | "license": "MIT", 20 | "ignore": [ 21 | "**/.*", 22 | "node_modules", 23 | "bower_components", 24 | "test", 25 | "tests" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /gulp/.eslintrc: -------------------------------------------------------------------------------- 1 | env: 2 | node: true 3 | mocha: true 4 | 5 | parserOptions: 6 | ecmaVersion: 8 7 | 8 | extends: 'eslint:recommended' 9 | 10 | rules: 11 | # Possible Errors 12 | no-console: "off" 13 | no-empty: "off" 14 | 15 | # Best Practices 16 | curly: "error" 17 | dot-notation: "error" 18 | eqeqeq: "error" 19 | no-return-assign: "error" 20 | no-proto: "error" 21 | no-case-declarations: "off" 22 | 23 | # Strict Mode 24 | strict: ["error", "global"] 25 | 26 | # Variables 27 | 28 | # Stylistic Issues 29 | camelcase: "error" 30 | comma-dangle: ["error", "never"] 31 | comma-spacing: "error" 32 | indent: ["error", 2] 33 | key-spacing: "error" 34 | linebreak-style: ["error", "unix"] 35 | new-cap: "error" 36 | quotes: ["error", "single"] 37 | semi: ["error", "always"] 38 | space-unary-ops: "error" 39 | 40 | # ECMAScript 6 41 | no-var: "error" 42 | 43 | # Node.js 44 | callback-return: "error" 45 | -------------------------------------------------------------------------------- /gulp/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": ["define", "Symbol"], 3 | 4 | "indent": 2, 5 | 6 | "bitwise": false, 7 | "camelcase": false, 8 | "curly": false, 9 | "eqeqeq": true, 10 | "forin": false, 11 | "immed": true, 12 | "latedef": false, 13 | "newcap": false, 14 | "noarg": true, 15 | "noempty": false, 16 | "nonew": false, 17 | "plusplus": false, 18 | "quotmark": false, 19 | "regexp": false, 20 | "undef": true, 21 | "unused": true, 22 | "strict": true, 23 | "trailing": true, 24 | "maxparams": false, 25 | "maxdepth": false, 26 | "maxstatements": false, 27 | "maxcomplexity": false, 28 | "maxlen": false, 29 | 30 | "boss": false, 31 | "debug": false, 32 | "eqnull": true, 33 | "evil": true, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "lastsemic": false, 38 | "laxbreak": false, 39 | "laxcomma": true, 40 | "loopfunc": false, 41 | "multistr": false, 42 | "onecase": false, 43 | "proto": true, 44 | "regexdash": false, 45 | "scripturl": true, 46 | "smarttabs": false, 47 | "shadow": false, 48 | "sub": false, 49 | "supernew": false, 50 | "validthis": false, 51 | 52 | "browser": true, 53 | "jquery": true, 54 | "node": true, 55 | "worker": true, 56 | 57 | "nomen": false, 58 | "onevar": false, 59 | "white": false, 60 | 61 | "-W018": true, 62 | 63 | "esversion": 6 64 | } 65 | -------------------------------------------------------------------------------- /gulp/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | jscs: { 5 | dirnames: ['./lib/async.js', './perf/**', './test/**/*.js', './gulp/**'], 6 | }, 7 | jsbeautifier: { 8 | dirnames: ['./lib/async.js', './perf/**', './test/**/*.js', './gulp/**'], 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /gulp/tasks/gh-pages.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | const gulp = require('gulp'); 7 | const git = require('gulp-git'); 8 | 9 | const async = require('../../'); 10 | const jsdoc = require('./jsdoc'); 11 | 12 | gulp.task('gh-pages', (done) => { 13 | const filepath = path.resolve(__dirname, '../..', 'lib/async.js'); 14 | const options = { 15 | encoding: 'utf8', 16 | }; 17 | const asyncFile = fs.readFileSync(filepath, options); 18 | async.angelFall( 19 | [ 20 | async.apply(git.fetch, 'origin', ''), 21 | 22 | async.apply(git.checkout, 'gh-pages'), 23 | 24 | async.apply(fs.writeFile, filepath, asyncFile, { 25 | encoding: 'utf8', 26 | }), 27 | 28 | async.apply(jsdoc.create), 29 | 30 | async.apply(git.status, { 31 | args: '-s ./doc', 32 | }), 33 | 34 | (result, next) => { 35 | if (!result) { 36 | console.log('[skip commit]'); 37 | return checkoutMaster(done); 38 | } 39 | git.exec( 40 | { 41 | args: 'add ./doc ./lib/async.js', 42 | }, 43 | next 44 | ); 45 | }, 46 | 47 | async.apply(git.exec, { 48 | args: `commit -m "docs(jsdoc): update jsdoc [v${async.VERSION}] [ci skip]"`, 49 | }), 50 | 51 | checkoutMaster, 52 | ], 53 | done 54 | ); 55 | 56 | function checkoutMaster(next) { 57 | git.checkout('master', next); 58 | } 59 | }); 60 | -------------------------------------------------------------------------------- /gulp/tasks/jscs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const jscs = require('gulp-jscs'); 5 | 6 | const config = require('../config'); 7 | 8 | gulp.task('jscs', () => { 9 | const { dirnames } = config.jscs; 10 | return gulp.src(dirnames).pipe(jscs('.jscsrc')); 11 | }); 12 | -------------------------------------------------------------------------------- /gulp/tasks/jsdoc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const exec = require('child_process').exec; 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | const gulp = require('gulp'); 8 | 9 | const config = JSON.parse( 10 | fs.readFileSync(path.resolve(__dirname, '../..', '.jsdocrc'), { 11 | encoding: 'utf8', 12 | }) 13 | ); 14 | 15 | function createJSDoc(done) { 16 | const dirpath = path.resolve(__dirname, '../..', config.opts.destination); 17 | exec(`rm -rf ${dirpath}`); 18 | exec('$(npm bin)/jsdoc -c .jsdocrc ./lib/async.js', done); 19 | } 20 | 21 | gulp.task('jsdoc', createJSDoc); 22 | 23 | exports.create = createJSDoc; 24 | -------------------------------------------------------------------------------- /gulp/tasks/minify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const qs = require('querystring'); 5 | const path = require('path'); 6 | const http = require('http'); 7 | const { exec } = require('child_process'); 8 | 9 | const gulp = require('gulp'); 10 | 11 | const filepath = path.resolve(__dirname, '../..', 'lib', 'async.js'); 12 | const target = path.resolve(__dirname, '../..', 'lib', 'async.min.js'); 13 | 14 | gulp.task('minify:local', (done) => { 15 | const compilerPath = path.resolve(__dirname, '..', 'compiler.jar'); 16 | const command = `java -jar ${compilerPath} --js ${filepath} --js_output_file ${target}`; 17 | exec(command, done); 18 | }); 19 | 20 | gulp.task('minify', (done) => { 21 | const file = fs.readFileSync(filepath, 'utf8'); 22 | const body = qs.stringify({ 23 | js_code: file, 24 | compilation_level: 'SIMPLE_OPTIMIZATIONS', 25 | // compilation_level: 'ADVANCED_OPTIMIZATIONS', 26 | output_format: 'text', 27 | output_info: 'compiled_code', 28 | }); 29 | const opts = { 30 | hostname: 'closure-compiler.appspot.com', 31 | port: 80, 32 | path: '/compile', 33 | method: 'POST', 34 | headers: { 35 | 'Content-Type': 'application/x-www-form-urlencoded', 36 | Content_length: Buffer.byteLength(file), 37 | }, 38 | }; 39 | let data = ''; 40 | const req = http 41 | .request(opts, (res) => { 42 | res 43 | .setEncoding('utf8') 44 | .on('data', (res) => { 45 | data += res; 46 | }) 47 | .on('error', done) 48 | .on('end', () => { 49 | fs.writeFile(target, data, 'utf8', done); 50 | }); 51 | }) 52 | .on('error', done); 53 | req.write(body); 54 | req.end(); 55 | }); 56 | -------------------------------------------------------------------------------- /gulp/tasks/npm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | const _ = require('lodash'); 6 | const gulp = require('gulp'); 7 | const fs = require('fs-extra'); 8 | const argv = require('minimist')(process.argv.slice(2)); 9 | 10 | const { exec } = require('../util'); 11 | const async = require('../../lib/async'); 12 | 13 | gulp.task('npm:publish', publish); 14 | 15 | async function publish() { 16 | const { otp } = argv; 17 | if (!otp) { 18 | throw new Error('Invalid otp'); 19 | } 20 | const rootpath = path.resolve(__dirname, '../..'); 21 | const buildpath = path.resolve(rootpath, 'build'); 22 | 23 | await exec(`rm -rf ${buildpath}`); 24 | 25 | // make dir 26 | !fs.existsSync(buildpath) && fs.mkdirSync(buildpath); 27 | 28 | // copy lib 29 | fs.copySync(path.resolve(rootpath, 'lib', 'async.js'), path.resolve(buildpath, 'async.js')); 30 | // copy the minified file 31 | fs.copySync( 32 | path.resolve(rootpath, 'dist', 'async.min.js'), 33 | path.resolve(buildpath, 'async.min.js') 34 | ); 35 | 36 | // copy package.json 37 | const json = _.omit(require('../../package'), ['files', 'scripts', 'private']); 38 | json.main = 'async.js'; 39 | json.browser = 'async.min.js'; 40 | fs.writeFileSync(path.resolve(buildpath, 'package.json'), JSON.stringify(json, null, 2), 'utf8'); 41 | 42 | // copy README 43 | fs.copySync(path.resolve(rootpath, 'README.md'), path.resolve(buildpath, 'README.md')); 44 | 45 | // copy LICENSE 46 | fs.copySync(path.resolve(rootpath, 'LICENSE'), path.resolve(buildpath, 'LICENSE')); 47 | 48 | // create all function files 49 | const template = fs.readFileSync(path.resolve(__dirname, '../template'), 'utf8'); 50 | _.forOwn(async, (func, key) => { 51 | if (!_.isFunction(func)) { 52 | return; 53 | } 54 | const file = template.replace('', key); 55 | fs.writeFileSync(path.resolve(buildpath, `${key}.js`), file, 'utf8'); 56 | }); 57 | 58 | await exec(`cd ${buildpath} && npm publish --otp=${otp}`); 59 | } 60 | -------------------------------------------------------------------------------- /gulp/tasks/release.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | const _ = require('lodash'); 7 | const gulp = require('gulp'); 8 | const git = require('gulp-git'); 9 | const bump = require('gulp-bump'); 10 | const tagVersion = require('gulp-tag-version'); 11 | 12 | const basepath = path.resolve(__dirname, '../../'); 13 | const packagepath = path.resolve(basepath, 'package.json'); 14 | const bowerpath = path.resolve(basepath, 'bower.json'); 15 | const types = ['patch', 'prepatch', 'minor', 'preminor', 'major', 'premajor']; 16 | const { version: prevVersion } = require(packagepath); 17 | 18 | gulp.task('release:async', async () => { 19 | delete require.cache[packagepath]; 20 | const { version } = require(packagepath); 21 | const asyncpath = path.resolve(basepath, 'lib', 'async.js'); 22 | const file = fs.readFileSync(asyncpath, 'utf8'); 23 | fs.writeFileSync(asyncpath, file.replace(new RegExp(prevVersion, 'g'), version), 'utf8'); 24 | }); 25 | 26 | gulp.task('release:tag', () => { 27 | return gulp.src(packagepath).pipe(tagVersion()); 28 | }); 29 | 30 | gulp.task('release:dist', async () => { 31 | _.forEach(['async.js', 'async.min.js'], (file) => { 32 | const filepath = path.resolve(basepath, 'lib', file); 33 | const distpath = path.resolve(basepath, 'dist', file); 34 | fs.createReadStream(filepath).pipe(fs.createWriteStream(distpath)); 35 | }); 36 | }); 37 | 38 | gulp.task('release:commit', () => { 39 | delete require.cache[packagepath]; 40 | const { version } = require(packagepath); 41 | return gulp.src(['./dist/*', './lib/*', packagepath, bowerpath]).pipe(git.commit(version)); 42 | }); 43 | 44 | function updatePackageVersion(type) { 45 | return () => { 46 | return gulp.src([packagepath, bowerpath]).pipe(bump({ type })).pipe(gulp.dest('./')); 47 | }; 48 | } 49 | 50 | _.forEach(types, (type) => { 51 | gulp.task(`release:package:${type}`, updatePackageVersion(type)); 52 | gulp.task( 53 | `release:${type}`, 54 | gulp.series( 55 | `release:package:${type}`, 56 | 'release:async', 57 | 'minify:local', 58 | 'release:dist', 59 | 'release:commit', 60 | 'release:tag', 61 | 'gh-pages' 62 | ) 63 | ); 64 | }); 65 | -------------------------------------------------------------------------------- /gulp/tasks/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | const _ = require('lodash'); 7 | const gulp = require('gulp'); 8 | const exit = require('gulp-exit'); 9 | const mocha = require('gulp-mocha'); 10 | const gutil = require('gulp-util'); 11 | const executor = require('mocha-parallel-executor'); 12 | 13 | const config = require('../../test/config'); 14 | 15 | function test() { 16 | const filename = gutil.env.file || '*'; 17 | const delay = gulp.env.delay; 18 | if (delay) { 19 | config.delay = delay; 20 | } 21 | gulp 22 | .src([`./test/**/test.${filename}*`]) 23 | .pipe( 24 | mocha({ 25 | reporter: 'spec', 26 | report: 'lcovonly', 27 | timeout: 2000, 28 | }) 29 | ) 30 | .pipe(exit()); 31 | } 32 | 33 | function exec(name, func) { 34 | const filepath = path.resolve(__dirname, '../..', 'lib', name); 35 | const filename = gutil.env.file; 36 | let files; 37 | if (filename) { 38 | files = _.transform(['collections', 'controlFlow', 'other', 'utils'], (result, dir) => { 39 | const p = path.resolve(__dirname, '../../', 'test', dir, `test.${filename}.js`); 40 | if (fs.existsSync(p)) { 41 | result.push(p); 42 | } 43 | }); 44 | } 45 | global.async = require(filepath); 46 | global.async_path = filepath; 47 | func({ files: files }); 48 | } 49 | 50 | gulp.task('test', () => { 51 | exec('async.js', test); 52 | }); 53 | 54 | gulp.task('test:min', () => { 55 | exec('async.min.js', test); 56 | }); 57 | 58 | gulp.task('test:fast', () => { 59 | exec('async.js', executor); 60 | }); 61 | 62 | gulp.task('test:fast:min', () => { 63 | exec('async.min.js', executor); 64 | }); 65 | -------------------------------------------------------------------------------- /gulp/template: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./async').; 4 | -------------------------------------------------------------------------------- /gulp/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const cp = require('child_process'); 4 | 5 | const _ = require('lodash'); 6 | const Aigle = require('aigle'); 7 | 8 | module.exports = { exec, spawn }; 9 | 10 | function exec(command, args) { 11 | command = !args ? command : _.reduce(args, (str, arg) => `${str} ${arg}`, command); 12 | return execute(cp.exec, command); 13 | } 14 | 15 | function spawn(name, args) { 16 | return execute(cp.spawn, name, args); 17 | } 18 | 19 | function execute(func, command, args) { 20 | return new Aigle((resolve, reject) => { 21 | let result = ''; 22 | const task = func(command, args); 23 | task.on('close', (err) => (err ? reject(err) : resolve(result))); 24 | task.on('error', reject); 25 | task.stdout.on('data', (data) => (result += `${data}`)); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./test/config'); 4 | 5 | var requireDir = require('require-dir'); 6 | 7 | requireDir('./gulp/tasks', { recurse: true }); 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neo-async", 3 | "version": "2.6.2", 4 | "description": "Neo-Async is a drop-in replacement for Async, it almost fully covers its functionality and runs faster ", 5 | "main": "lib/async.js", 6 | "scripts": { 7 | "test": "istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -R spec ./test --recursive", 8 | "clean": "rm -rf coverage", 9 | "cov:100": "grep Lines | perl -nle 'my ($l, $c, $p, @d) = split(/[\\s%]+/); exit(($p == 100) == 0)'" 10 | }, 11 | "license": "MIT", 12 | "keywords": [ 13 | "async", 14 | "util" 15 | ], 16 | "private": true, 17 | "repository": { 18 | "type": "git", 19 | "url": "git@github.com:suguru03/neo-async.git" 20 | }, 21 | "homepage": "https://github.com/suguru03/neo-async", 22 | "files": [ 23 | "LICENSE", 24 | "index.js", 25 | "lib/async.js", 26 | "lib/async.min.js", 27 | "dist/async.js", 28 | "dist/async.min.js" 29 | ], 30 | "dependencies": {}, 31 | "devDependencies": { 32 | "aigle": "^1.14.0", 33 | "async": "^2.6.0", 34 | "benchmark": "^2.1.1", 35 | "bluebird": "^3.5.1", 36 | "codecov.io": "^0.1.6", 37 | "fs-extra": "^4.0.2", 38 | "func-comparator": "^0.7.2", 39 | "gulp": "^4.0.2", 40 | "gulp-bump": "^2.8.0", 41 | "gulp-exit": "0.0.2", 42 | "gulp-git": "^2.4.2", 43 | "gulp-jscs": "^4.0.0", 44 | "gulp-mocha": "^4.2.0", 45 | "gulp-tag-version": "^1.3.0", 46 | "gulp-util": "^3.0.7", 47 | "husky": "^4.2.5", 48 | "istanbul": "^0.4.3", 49 | "jsdoc": "^3.5.5", 50 | "jshint": "^2.9.5", 51 | "lint-staged": "^10.2.11", 52 | "lodash": "^4.17.19", 53 | "minimist": "^1.2.3", 54 | "mocha": "^3.5.3", 55 | "mocha-parallel-executor": "^0.3.0", 56 | "mocha.parallel": "^0.15.3", 57 | "prettier": "^2.0.5" 58 | }, 59 | "husky": { 60 | "hooks": { 61 | "pre-commit": "lint-staged" 62 | } 63 | }, 64 | "lint-staged": { 65 | "*.{js,ts}": [ 66 | "prettier --write" 67 | ] 68 | }, 69 | "prettier": { 70 | "printWidth": 100, 71 | "singleQuote": true 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /perf/README.md: -------------------------------------------------------------------------------- 1 | # benchmark 2 | 3 | The benchmark tool is using `benchmark.js` and `func-comparator`. 4 | 5 | ## How to execute 6 | 7 | ```bash 8 | // execute all cases 9 | $ node ./ 10 | 11 | // specify benchmark tool 12 | $ node ./ -b benchmark // ['benchmark', 'func-comparator'] 13 | $ node ./ -b bench 14 | $ node ./ --benchmark func 15 | 16 | // specify function name 17 | $ node ./ --target each // all `each` tasks 18 | $ node ./ --target each:array // only `each:array` task 19 | 20 | // specify times (only func-comparator) 21 | $ node ./ -t 10 22 | $ node ./ --times 10 23 | ``` 24 | 25 | ## Sample 26 | 27 | ```bash 28 | $ node ./ --target each 29 | 30 | ====================================== 31 | [async], v2.0.0-rc.4 32 | [neo_async], v2.0.0_pre 33 | ====================================== 34 | [each:array] Comparating... 35 | -------------------------------------- 36 | [benchmark] Executing... 37 | [1] "neo_async" 7.30μs[1.00][1.00] 38 | [2] "async" 22.0μs[0.332][3.01] 39 | -------------------------------------- 40 | [func-comparator] Executing... 41 | [1] "neo_async" 80.4μs[1.00][1.00] 42 | [2] "async" 185μs[0.435][2.30] 43 | ====================================== 44 | [each:object] Comparating... 45 | -------------------------------------- 46 | [benchmark] Executing... 47 | [1] "neo_async" 14.6μs[1.00][1.00] 48 | [2] "async" 32.0μs[0.456][2.19] 49 | -------------------------------------- 50 | [func-comparator] Executing... 51 | [1] "neo_async" 135μs[1.00][1.00] 52 | [2] "async" 236μs[0.572][1.75] 53 | ====================================== 54 | [each:map] Comparating... 55 | -------------------------------------- 56 | [benchmark] Executing... 57 | [1] "neo_async" 9.44μs[1.00][1.00] 58 | [2] "async" 31.7μs[0.297][3.36] 59 | -------------------------------------- 60 | [func-comparator] Executing... 61 | [1] "neo_async" 86.4μs[1.00][1.00] 62 | [2] "async" 238μs[0.363][2.75] 63 | ``` 64 | -------------------------------------------------------------------------------- /perf/benchmark/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Benchmark = require('benchmark'); 5 | 6 | module.exports = function(funcs) { 7 | 8 | return function(callback) { 9 | var suite = new Benchmark.Suite(); 10 | var total = {}; 11 | _.forEach(funcs, function(func, key) { 12 | total[key] = { 13 | count: 0, 14 | time: 0 15 | }; 16 | suite.add(key, { 17 | defer: true, 18 | fn: function(deferred) { 19 | var start = process.hrtime(); 20 | func(function() { 21 | var diff = process.hrtime(start); 22 | total[key].time += (diff[0] * 1e9 + diff[1]) / 1000; 23 | total[key].count++; 24 | deferred.resolve(); 25 | }); 26 | } 27 | }); 28 | }); 29 | 30 | suite 31 | .on('complete', function() { 32 | var result = _.chain(this) 33 | .map(function(data) { 34 | var name = data.name; 35 | var time = total[name]; 36 | return { 37 | name: name, 38 | mean: time.time / time.count 39 | }; 40 | }) 41 | .sortBy('mean') 42 | .value(); 43 | callback(null, result); 44 | }) 45 | .run({ 46 | async: true 47 | }); 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /perf/func-comparator/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Comparator = require('func-comparator').Comparator; 5 | 6 | module.exports = function(funcs, times) { 7 | 8 | return function(callback) { 9 | new Comparator() 10 | .set(funcs) 11 | .async() 12 | .times(times) 13 | .start() 14 | .result(function(err, res) { 15 | if (err) { 16 | return callback(err); 17 | } 18 | var result = _.chain(res) 19 | .map(function(data, name) { 20 | return { 21 | name: name, 22 | mean: data.average 23 | }; 24 | }) 25 | .sortBy('mean') 26 | .value(); 27 | 28 | callback(null, result); 29 | }); 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /perf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | var argv = require('minimist')(process.argv.slice(2)); 6 | 7 | var benchmark = argv.b || argv.benchmark; // ['benchmark', 'func-comparator'], -b func-comparator 8 | var count = argv.c || argv.count; 9 | var times = argv.t || argv.times; 10 | var target = argv.target; // -t 11 | 12 | var benchmarks = _.filter([ 13 | 'benchmark', 14 | 'func-comparator' 15 | ], function(name) { 16 | return benchmark ? RegExp(benchmark).test(name) : name; 17 | }); 18 | benchmarks = _.transform(benchmarks, function(result, name) { 19 | result[name] = require('./' + name); 20 | }, {}); 21 | 22 | var async = require('../'); 23 | var functions = { 24 | async: require('async'), 25 | neo_async: async 26 | }; 27 | functions.async.VERSION = require('async/package.json').version; 28 | 29 | console.log('======================================'); 30 | _.forOwn(functions, function(obj, key) { 31 | console.log('[%s], v%s', key, obj.VERSION); 32 | }); 33 | 34 | var config = require('./config'); 35 | var defaults = config.defaults; 36 | var tasks = _.omit(config, 'defaults'); 37 | if (target) { 38 | var reg = new RegExp('^' + target + '$'); 39 | tasks = _.pickBy(tasks, function(obj, name) { 40 | return reg.test(name) || reg.test(_.first(name.split(':'))); 41 | }); 42 | } 43 | 44 | async.eachSeries(tasks, function(task, name, done) { 45 | var avaiable = task.avaiable === undefined ? defaults.avaiable : task.avaiable; 46 | if (!avaiable) { 47 | return done(); 48 | } 49 | var _count = count || _.get(task, 'count', defaults.count); 50 | var _times = times || _.get(task, 'times', defaults.times); 51 | var setup = _.get(task, 'setup', _.noop); 52 | 53 | setup(_count); 54 | 55 | console.log('======================================'); 56 | console.log('[' + name + '] Comparating... '); 57 | 58 | var func = _.get(task, 'func', defaults.func); 59 | async.eachSeries(benchmarks, function(benchmarker, benchmark, next) { 60 | var funcs = _.mapValues(functions, function(async) { 61 | return function(callback) { 62 | func(async, callback); 63 | }; 64 | }); 65 | console.log('--------------------------------------'); 66 | console.log('[%s] Executing...', benchmark); 67 | benchmarker(funcs, _times)(function(err, res) { 68 | if (err) { 69 | return next(err); 70 | } 71 | _.forEach(res, function(data, index, array) { 72 | var name = data.name; 73 | var mean = data.mean; 74 | var diff = (_.first(array).mean) / mean; 75 | var rate = mean / (_.first(array).mean); 76 | console.log('[%d] "%s" %sμs[%s][%s]', ++index, name, mean.toPrecision(3), diff.toPrecision(3), rate.toPrecision(3)); 77 | }); 78 | next(); 79 | }); 80 | }, done); 81 | }); 82 | -------------------------------------------------------------------------------- /test/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof Symbol !== 'function') { 4 | global.Symbol = function() {}; 5 | global.Symbol.iterator = 'symbol'; 6 | } 7 | 8 | module.exports = { 9 | delay: process.env.DELAY || 70 10 | }; 11 | -------------------------------------------------------------------------------- /test/controlFlow/test.angelFall.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var _ = require('lodash'); 8 | var parallel = require('mocha.parallel'); 9 | 10 | var async = global.async || require('../../'); 11 | var delay = require('../config').delay; 12 | var util = require('../util'); 13 | 14 | function createSimpleTasks(numbers) { 15 | 16 | var first = true; 17 | var tasks = _.transform(numbers, function(memo, num, key) { 18 | if (first) { 19 | first = false; 20 | memo[key] = function(done) { 21 | if (this === Math) { 22 | num *= 2; 23 | } 24 | done(null, num); 25 | }; 26 | } else { 27 | memo[key] = function(sum, done) { 28 | if (this === Math) { 29 | num *= 2; 30 | } 31 | done(null, sum + num); 32 | }; 33 | } 34 | }); 35 | return tasks; 36 | } 37 | 38 | parallel('#angelFall', function() { 39 | 40 | it('should execute to waterfall by collection of array', function(done) { 41 | 42 | var numbers = [1, 3, 2, 4]; 43 | var tasks = createSimpleTasks(numbers); 44 | async.angelFall(tasks, function(err, res) { 45 | if (err) { 46 | return done(err); 47 | } 48 | assert.strictEqual(res, 10); 49 | done(); 50 | }); 51 | }); 52 | 53 | it('should execute simple tasks', function(done) { 54 | 55 | var numbers = [1, 3, 2, 4, 7, 8, 6, 5]; 56 | var tasks = createSimpleTasks(numbers); 57 | async.angelFall(tasks, function(err, result) { 58 | if (err) { 59 | return done(err); 60 | } 61 | assert.strictEqual(result, 36); 62 | done(); 63 | }); 64 | }); 65 | 66 | it('should execute example tasks', function(done) { 67 | var order = []; 68 | var tasks = [ 69 | function(next) { 70 | setTimeout(function() { 71 | order.push(1); 72 | next(null, 1); 73 | }, 10); 74 | }, 75 | function(arg1, empty, next) { 76 | setTimeout(function() { 77 | order.push(2); 78 | next(null, 1, 2); 79 | }, 30); 80 | }, 81 | function(next) { 82 | setTimeout(function() { 83 | order.push(3); 84 | next(null, 3); 85 | }, 20); 86 | }, 87 | function(arg1, empty1, empty2, empty3, next) { 88 | setTimeout(function() { 89 | order.push(4); 90 | next(null, 1, 2, 3, 4); 91 | }, 40); 92 | } 93 | ]; 94 | async.angelFall(tasks, function(err, arg1, arg2, arg3, arg4) { 95 | if (err) { 96 | return done(err); 97 | } 98 | assert.strictEqual(arg1, 1); 99 | assert.strictEqual(arg2, 2); 100 | assert.strictEqual(arg3, 3); 101 | assert.strictEqual(arg4, 4); 102 | done(); 103 | }); 104 | }); 105 | 106 | it('should execute complex tasks', function(done) { 107 | 108 | var tasks = [ 109 | function(next) { 110 | next(null, 1); 111 | }, 112 | function(arg1, next) { 113 | next(null, arg1, 2); 114 | }, 115 | function(arg1, arg2, empty, next) { 116 | next(null, arg1, arg2, 3); 117 | }, 118 | function(arg1, arg2, arg3, empty1, empty2, empty3, empty4, next) { 119 | next(null, arg1, arg2, arg3, 4); 120 | }, 121 | function(arg1, next) { 122 | next(null, arg1, 2, 3, 4, 5); 123 | }, 124 | function(next) { 125 | next(null, 1, 2, 3, 4, 5, 6, 7, 8); 126 | }, 127 | function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, empty, next) { 128 | next(null, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, empty, next); 129 | } 130 | ]; 131 | async.angelFall(tasks, function(err, a, b, c, d, e, f, g, h, empty) { 132 | if (err) { 133 | return done(err); 134 | } 135 | assert.strictEqual(a, 1); 136 | assert.strictEqual(b, 2); 137 | assert.strictEqual(c, 3); 138 | assert.strictEqual(d, 4); 139 | 140 | assert.strictEqual(e, 5); 141 | assert.strictEqual(f, 6); 142 | assert.strictEqual(g, 7); 143 | assert.strictEqual(h, 8); 144 | 145 | assert.strictEqual(empty, undefined); 146 | 147 | done(); 148 | }); 149 | }); 150 | 151 | it('should execute even if task does not have an argument', function(done) { 152 | 153 | var order = []; 154 | async.angelFall([ 155 | function() { 156 | order.push(1); 157 | return 1; 158 | }, 159 | function(next) { 160 | order.push(2); 161 | next(); 162 | }, 163 | function(arg, next) { 164 | order.push(3); 165 | next(); 166 | }, 167 | function() { 168 | order.push(4); 169 | return 4; 170 | }, 171 | function(arg, next) { 172 | assert.strictEqual(arg, 4); 173 | order.push(5); 174 | next(); 175 | } 176 | ], function(err) { 177 | if (err) { 178 | return done(err); 179 | } 180 | assert.deepStrictEqual(order, [1, 2, 3, 4, 5]); 181 | done(); 182 | }); 183 | }); 184 | 185 | it('should throw error', function(done) { 186 | 187 | var numbers = [1, 3, 2, 4]; 188 | var tasks = createSimpleTasks(numbers); 189 | var errorTask = function(res, next) { 190 | next('error'); 191 | }; 192 | tasks.splice(2, 0, errorTask); 193 | 194 | async.angelFall(tasks, function(err) { 195 | assert.ok(err); 196 | done(); 197 | }); 198 | }); 199 | 200 | it('should throw error if callback is called twice', function(done) { 201 | 202 | var errorCallCount = 0; 203 | setTimeout(function() { 204 | assert.strictEqual(errorCallCount, 1); 205 | done(); 206 | }, delay); 207 | 208 | domain.create() 209 | .on('error', util.errorChecker) 210 | .on('error', function() { 211 | errorCallCount++; 212 | }) 213 | .run(function() { 214 | var array = [ 215 | function(next) { 216 | setImmediate(function() { 217 | next(null, 'one', 'two'); 218 | }); 219 | setImmediate(function() { 220 | next(null, 'one', 'two'); 221 | }); 222 | }, 223 | function(arg1, arg2, next) { 224 | next(null, arg1, arg2, 'three'); 225 | }, 226 | function(arg1, arg2, arg3, next) { 227 | next(null, 'four'); 228 | }, 229 | function(arg1, next) { 230 | next(); 231 | } 232 | ]; 233 | async.angelFall(array); 234 | }); 235 | }); 236 | 237 | it('should throw error if task is not collection', function(done) { 238 | 239 | async.angelFall(null, function(err) { 240 | assert.strictEqual(err.message, 'First argument to waterfall must be an array of functions'); 241 | done(); 242 | }); 243 | }); 244 | 245 | it('should throw error with binding', function(done) { 246 | 247 | var numbers = [1, 3, 2, 4]; 248 | var tasks = createSimpleTasks(numbers); 249 | var errorTask = function(res, next) { 250 | next('error'); 251 | }; 252 | tasks.splice(2, 0, errorTask); 253 | 254 | async.angelFall(tasks, function(err) { 255 | assert.ok(err); 256 | done(); 257 | }, Math); 258 | }); 259 | 260 | it('should throw error if task which does not have an argument throws error', function(done) { 261 | 262 | var order = []; 263 | async.angelFall([ 264 | function() { 265 | order.push(1); 266 | return 1; 267 | }, 268 | function(next) { 269 | order.push(2); 270 | next(); 271 | }, 272 | function(arg, next) { 273 | order.push(3); 274 | next(); 275 | }, 276 | function() { 277 | order.push(4); 278 | throw new Error('error'); 279 | }, 280 | function(arg, next) { 281 | order.push(5); 282 | next(); 283 | } 284 | ], function(err) { 285 | assert.ok(err); 286 | assert.deepStrictEqual(order, [1, 2, 3, 4]); 287 | done(); 288 | }); 289 | }); 290 | 291 | it('should avoid double callback', function(done) { 292 | 293 | var called = false; 294 | var tasks = _.times(3, function(n) { 295 | return function(callback) { 296 | try { 297 | callback('error' + n); 298 | } catch (exception) { 299 | try { 300 | callback(exception); 301 | } catch(e) { 302 | assert.ok(e); 303 | util.errorChecker(e); 304 | } 305 | done(); 306 | } 307 | }; 308 | }); 309 | async.angelFall(tasks, function(err) { 310 | assert.ok(err); 311 | assert.strictEqual(called, false); 312 | called = true; 313 | async.nothing(); 314 | }); 315 | }); 316 | 317 | it('should return response immediately if array task is empty', function(done) { 318 | 319 | var tasks = []; 320 | async.angelFall(tasks, function(err, res) { 321 | if (err) { 322 | return done(err); 323 | } 324 | assert.strictEqual(res, undefined); 325 | done(); 326 | }); 327 | }); 328 | 329 | }); 330 | -------------------------------------------------------------------------------- /test/controlFlow/test.apply.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | 11 | parallel('#apply', function() { 12 | 13 | it('should apply arguments', function() { 14 | 15 | var func = function() { 16 | assert.deepStrictEqual(Array.prototype.slice.call(arguments), [1, 2, 3, 4]); 17 | }; 18 | 19 | async.apply(func, 1, 2, 3, 4)(); 20 | async.apply(func, 1, 2, 3)(4); 21 | async.apply(func, 1, 2)(3, 4); 22 | async.apply(func, 1)(2, 3, 4); 23 | 24 | var fn = async.apply(func); 25 | fn(1, 2, 3, 4); 26 | fn(1, 2, 3, 4); 27 | 28 | assert.strictEqual( 29 | async.apply(function(name) { 30 | return 'hello ' + name; 31 | }, 'world')(), 32 | 'hello world' 33 | ); 34 | }); 35 | 36 | it('should apply long arguments', function() { 37 | 38 | var func = function(a1, a2, a3, a4, a5, a6, a7, a8) { 39 | assert.strictEqual(a8, 8); 40 | assert.strictEqual(_.sum(arguments), 55); 41 | }; 42 | var newFunc = async.apply(func, 1, 2, 3, 4, 5, 6, 7); 43 | assert.strictEqual(func.length, 8); 44 | assert.strictEqual(newFunc.length, 1); 45 | newFunc(8, 9, 10); 46 | }); 47 | 48 | it('should execute waterfall with apply', function(done) { 49 | 50 | async.waterfall([ 51 | function(next) { 52 | next(null, 1); 53 | }, 54 | async.apply(function(arg1, arg2, next) { 55 | assert.strictEqual(arg1, 0); 56 | assert.strictEqual(arg2, 1); 57 | next(); 58 | }, 0), 59 | async.apply(function(arg1, arg2, arg3, arg4, next) { 60 | assert.strictEqual(arg1, 'a'); 61 | assert.strictEqual(arg2, 'b'); 62 | assert.strictEqual(arg3, 'c'); 63 | assert.strictEqual(arg4, 'd'); 64 | next(null, 1, 2, 3); 65 | }, 'a', 'b', 'c', 'd') 66 | ], function(err, res1, res2, res3) { 67 | if (err) { 68 | return done(err); 69 | } 70 | assert.strictEqual(res1, 1); 71 | assert.strictEqual(res2, 2); 72 | assert.strictEqual(res3, 3); 73 | done(); 74 | }); 75 | }); 76 | 77 | it('should execute angelFall with apply', function(done) { 78 | 79 | async.angelFall([ 80 | function(next) { 81 | next(null, 1); 82 | }, 83 | async.apply(function(arg1, arg2, arg3, next) { 84 | assert.strictEqual(arg1, 0); 85 | assert.strictEqual(arg2, 1); 86 | assert.strictEqual(arg3, undefined); 87 | next(); 88 | }, 0), 89 | async.apply(function(arg1, arg2) { 90 | return arg1 + arg2; 91 | }, 1, 2), 92 | async.apply(function(arg1, arg2, arg3, arg4, arg5, arg6, next) { 93 | assert.strictEqual(arg1, 'a'); 94 | assert.strictEqual(arg2, 'b'); 95 | assert.strictEqual(arg3, 'c'); 96 | assert.strictEqual(arg4, 'd'); 97 | assert.strictEqual(arg5, 3); 98 | next(null, 1, 2, 3); 99 | }, 'a', 'b', 'c', 'd') 100 | ], function(err, res1, res2, res3) { 101 | if (err) { 102 | return done(err); 103 | } 104 | assert.strictEqual(res1, 1); 105 | assert.strictEqual(res2, 2); 106 | assert.strictEqual(res3, 3); 107 | done(); 108 | }); 109 | }); 110 | 111 | }); 112 | -------------------------------------------------------------------------------- /test/controlFlow/test.applyEach.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | var util = require('../util'); 11 | 12 | parallel('#applyEach', function() { 13 | 14 | it('should execute in parallel', function(done) { 15 | 16 | var order = []; 17 | var one = function(val, cb) { 18 | assert.equal(val, 5); 19 | setTimeout(function() { 20 | order.push(1); 21 | cb(null, 1); 22 | }, 100); 23 | }; 24 | var two = function(val, cb) { 25 | assert.equal(val, 5); 26 | setTimeout(function() { 27 | order.push(2); 28 | cb(null, 2); 29 | }, 50); 30 | }; 31 | var three = function(val, cb) { 32 | assert.equal(val, 5); 33 | setTimeout(function() { 34 | order.push(3); 35 | cb(null, 3); 36 | }, 150); 37 | }; 38 | 39 | async.applyEach([one, two, three], 5, function(err, res) { 40 | if (err) { 41 | return done(err); 42 | } 43 | assert.deepStrictEqual(order, [2, 1, 3]); 44 | assert.deepStrictEqual(res, [1, 2, 3]); 45 | done(); 46 | }); 47 | 48 | }); 49 | 50 | it('should execute as a partial apprication', function(done) { 51 | 52 | var order = []; 53 | var one = function(val, cb) { 54 | assert.equal(val, 5); 55 | setTimeout(function() { 56 | order.push(1); 57 | cb(null, 1); 58 | }, 100); 59 | }; 60 | var two = function(val, cb) { 61 | assert.equal(val, 5); 62 | setTimeout(function() { 63 | order.push(2); 64 | cb(null, 2); 65 | }, 50); 66 | }; 67 | var three = function(val, cb) { 68 | assert.equal(val, 5); 69 | setTimeout(function() { 70 | order.push(3); 71 | cb(null, 3); 72 | }, 150); 73 | }; 74 | 75 | async.applyEach([one, two, three])(5, function(err, res) { 76 | if (err) { 77 | return done(err); 78 | } 79 | assert.deepStrictEqual(order, [2, 1, 3]); 80 | assert.deepStrictEqual(res, [1, 2, 3]); 81 | done(); 82 | }); 83 | }); 84 | 85 | it('should avoid double callback', function(done) { 86 | 87 | var called = false; 88 | var tasks = _.times(3, function(n) { 89 | return function(val, callback) { 90 | try { 91 | callback(val + n); 92 | } catch(exception) { 93 | try { 94 | callback(exception); 95 | } catch(e) { 96 | assert.ok(e); 97 | util.errorChecker(e); 98 | } 99 | done(); 100 | } 101 | }; 102 | }); 103 | async.applyEach(tasks, 5, function(err) { 104 | assert.ok(err); 105 | assert.strictEqual(called, false); 106 | called = true; 107 | async.nothing(); 108 | }); 109 | }); 110 | 111 | }); 112 | 113 | parallel('#applyEachSeries', function() { 114 | 115 | it('should execute in series', function(done) { 116 | 117 | var order = []; 118 | var one = function(val, cb) { 119 | assert.equal(val, 5); 120 | setTimeout(function() { 121 | order.push(1); 122 | cb(null, 1); 123 | }, 100); 124 | }; 125 | var two = function(val, cb) { 126 | assert.equal(val, 5); 127 | setTimeout(function() { 128 | order.push(2); 129 | cb(null, 2); 130 | }, 50); 131 | }; 132 | var three = function(val, cb) { 133 | assert.equal(val, 5); 134 | setTimeout(function() { 135 | order.push(3); 136 | cb(null, 3); 137 | }, 150); 138 | }; 139 | 140 | async.applyEachSeries([one, two, three], 5, function(err, res) { 141 | if (err) { 142 | return done(err); 143 | } 144 | assert.deepStrictEqual(order, [1, 2, 3]); 145 | assert.deepStrictEqual(res, [1, 2, 3]); 146 | done(); 147 | }); 148 | }); 149 | 150 | it('should avoid double callback', function(done) { 151 | 152 | var called = false; 153 | var tasks = _.times(3, function(n) { 154 | return function(val, callback) { 155 | try { 156 | callback(val + n); 157 | } catch(exception) { 158 | try { 159 | callback(exception); 160 | } catch(e) { 161 | assert.ok(e); 162 | util.errorChecker(e); 163 | } 164 | done(); 165 | } 166 | }; 167 | }); 168 | async.applyEachSeries(tasks, 5, function(err) { 169 | assert.ok(err); 170 | assert.strictEqual(called, false); 171 | called = true; 172 | async.nothing(); 173 | }); 174 | }); 175 | }); 176 | -------------------------------------------------------------------------------- /test/controlFlow/test.auto.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | var delay = require('../config').delay; 11 | var util = require('../util'); 12 | 13 | parallel('#auto', function() { 14 | 15 | it('should execute in accordance with best order', function(done) { 16 | 17 | var order = []; 18 | var tasks = { 19 | task1: ['task2', function(results, callback) { 20 | setTimeout(function() { 21 | order.push('task1'); 22 | callback(); 23 | }, 25); 24 | }], 25 | task2: function(callback) { 26 | setTimeout(function() { 27 | order.push('task2'); 28 | callback(); 29 | }, 50); 30 | }, 31 | task3: ['task2', function(results, callback) { 32 | order.push('task3'); 33 | callback(); 34 | }], 35 | task4: ['task1', 'task2', function(results, callback) { 36 | order.push('task4'); 37 | callback(); 38 | }], 39 | task5: ['task2', function(results, callback) { 40 | setTimeout(function() { 41 | order.push('task5'); 42 | callback(); 43 | }, 0); 44 | }], 45 | task6: ['task2', function(results, callback) { 46 | order.push('task6'); 47 | callback(); 48 | }] 49 | }; 50 | 51 | async.auto(tasks, function(err) { 52 | if (err) { 53 | return done(err); 54 | } 55 | assert.deepStrictEqual(order, [ 56 | 'task2', 57 | 'task3', 58 | 'task6', 59 | 'task5', 60 | 'task1', 61 | 'task4' 62 | ]); 63 | done(); 64 | }); 65 | }); 66 | 67 | it('should execute in accordance with best order and get results', function(done) { 68 | 69 | var order = []; 70 | 71 | async.auto({ 72 | task1: ['task2', function(results, callback) { 73 | assert.strictEqual(results.task2, 'task2'); 74 | setTimeout(function() { 75 | order.push('task1'); 76 | callback(null, 'task1a', 'task1b'); 77 | }, 25); 78 | }], 79 | task2: function(callback) { 80 | setTimeout(function() { 81 | order.push('task2'); 82 | callback(null, 'task2'); 83 | }); 84 | }, 85 | task3: ['task2', function(results, callback) { 86 | assert.strictEqual(results.task2, 'task2'); 87 | order.push('task3'); 88 | callback(); 89 | }], 90 | task4: ['task1', 'task2', function(results, callback) { 91 | assert.deepStrictEqual(results.task1, ['task1a', 'task1b']); 92 | assert.strictEqual(results.task2, 'task2'); 93 | order.push('task4'); 94 | callback(null, 'task4'); 95 | }] 96 | }, function(err, results) { 97 | if (err) { 98 | return done(err); 99 | } 100 | assert.deepStrictEqual(order, ['task2', 'task3', 'task1', 'task4']); 101 | assert.deepStrictEqual(results, { 102 | task1: ['task1a', 'task1b'], 103 | task2: 'task2', 104 | task3: undefined, 105 | task4: 'task4' 106 | }); 107 | done(); 108 | }); 109 | }); 110 | 111 | it('should execute even if array task dosen\'t have nay dependencies', function(done) { 112 | 113 | var order = []; 114 | async.auto({ 115 | task1: function(callback) { 116 | order.push('task1'); 117 | callback(null, 'task1'); 118 | }, 119 | task2: ['task3', function(task3, callback) { 120 | order.push('task2'); 121 | callback(null, 'task2'); 122 | }], 123 | task3: [function(callback) { 124 | order.push('task3'); 125 | callback(null, 'task3'); 126 | }] 127 | }, function(err, results) { 128 | if (err) { 129 | return done(err); 130 | } 131 | assert.deepStrictEqual(order, [ 132 | 'task1', 133 | 'task3', 134 | 'task2' 135 | ]); 136 | assert.deepStrictEqual(results, { 137 | task1: 'task1', 138 | task2: 'task2', 139 | task3: 'task3' 140 | }); 141 | done(); 142 | }); 143 | }); 144 | 145 | it('should execute even if object is empty', function(done) { 146 | 147 | async.auto({}, done); 148 | }); 149 | 150 | it('should execute without callback', function(done) { 151 | 152 | var tasks = { 153 | task1: function(callback) { 154 | callback(); 155 | }, 156 | task2: ['task1', function(results, callback) { 157 | callback(); 158 | }] 159 | }; 160 | async.auto(tasks); 161 | setTimeout(done, delay); 162 | }); 163 | 164 | it('should execute without callback', function(done) { 165 | 166 | var tasks = { 167 | task1: function(callback) { 168 | callback(); 169 | }, 170 | task2: ['task1', function(results, callback) { 171 | callback(); 172 | }] 173 | }; 174 | async.auto(tasks, 1); 175 | setTimeout(done, delay); 176 | }); 177 | 178 | it('should throw error and get safe results', function(done) { 179 | 180 | var order = []; 181 | 182 | async.auto({ 183 | task1: ['task2', function(results, callback) { 184 | assert.strictEqual(results.task2, 'task2'); 185 | setTimeout(function() { 186 | order.push('task1'); 187 | callback(null, 'task1a', 'task1b'); 188 | }, 25); 189 | }], 190 | task2: function(callback) { 191 | setTimeout(function() { 192 | order.push('task2'); 193 | callback(null, 'task2'); 194 | }); 195 | }, 196 | task3: ['task2', function(results, callback) { 197 | assert.strictEqual(results.task2, 'task2'); 198 | order.push('task3'); 199 | callback('error', 'task3'); 200 | }], 201 | task4: ['task1', 'task2', function(results, callback) { 202 | assert.deepStrictEqual(results.task1, ['task1a', 'task1b']); 203 | assert.strictEqual(results.task2, 'task2'); 204 | order.push('task4'); 205 | callback(null, 'task4'); 206 | }] 207 | }, function(err, results) { 208 | assert.ok(err); 209 | assert.deepStrictEqual(order, ['task2', 'task3']); 210 | assert.deepStrictEqual(results, { 211 | task2: 'task2', 212 | task3: 'task3' 213 | }); 214 | done(); 215 | }); 216 | }); 217 | 218 | it('should avoid double callback', function(done) { 219 | 220 | var called = false; 221 | var tasks = { 222 | task1: function(callback) { 223 | try { 224 | callback('error'); 225 | } catch(exception) { 226 | try { 227 | callback(exception); 228 | } catch(e) { 229 | assert.ok(e); 230 | util.errorChecker(e); 231 | } 232 | done(); 233 | } 234 | } 235 | }; 236 | async.auto(tasks, function(err) { 237 | assert.ok(err); 238 | assert.strictEqual(called, false); 239 | called = true; 240 | async.nothing(); 241 | }); 242 | }); 243 | 244 | it('should execute in limited by concurrency', function(done) { 245 | var order = []; 246 | var tasks = { 247 | task1: function(callback) { 248 | order.push('task1'); 249 | callback(); 250 | }, 251 | task2: ['task1', function(results, callback) { 252 | setTimeout(function() { 253 | order.push('task2'); 254 | callback(); 255 | }, delay * 2); 256 | }], 257 | task3: ['task1', function(results, callback) { 258 | setTimeout(function() { 259 | order.push('task3'); 260 | callback(); 261 | }, delay * 2); 262 | }], 263 | task4: ['task1', function(results, callback) { 264 | setTimeout(function() { 265 | order.push('task4'); 266 | callback(); 267 | }, delay * 1); 268 | }], 269 | task5: ['task1', function(results, callback) { 270 | setTimeout(function() { 271 | order.push('task5'); 272 | callback(); 273 | }, delay * 1); 274 | }], 275 | task6: ['task1', function(results, callback) { 276 | setTimeout(function() { 277 | order.push('task6'); 278 | callback(); 279 | }, delay * 1); 280 | }] 281 | }; 282 | async.auto(tasks, 2, function(err) { 283 | if (err) { 284 | return done(err); 285 | } 286 | assert.deepStrictEqual(order, [ 287 | 'task1', 288 | 'task2', 289 | 'task3', 290 | 'task4', 291 | 'task5', 292 | 'task6' 293 | ]); 294 | done(); 295 | }); 296 | }); 297 | 298 | it('should throw error if double callback', function(done) { 299 | 300 | domain.create() 301 | .on('error', util.errorChecker) 302 | .on('error', function() { 303 | done(); 304 | }) 305 | .run(function() { 306 | async.auto({ 307 | task1: function(callback) { 308 | setImmediate(function() { 309 | callback(); 310 | callback(); 311 | }); 312 | }, 313 | task2: function(callback) { 314 | callback(); 315 | } 316 | }); 317 | }); 318 | }); 319 | 320 | it('should stop execution if a synchronous error occur', function(done) { 321 | 322 | async.auto({ 323 | task1: function(callback) { 324 | callback('error'); 325 | }, 326 | task2: function(callback) { 327 | assert.ok(false); 328 | callback(); 329 | } 330 | }, 1, function(err) { 331 | assert.strictEqual(err, 'error'); 332 | setTimeout(done, delay); 333 | }); 334 | }); 335 | 336 | it('should avoid unnecessary deferrals', function(done) { 337 | 338 | var sync = true; 339 | async.auto({ 340 | task1: function(callback) { 341 | callback(null, 1); 342 | }, 343 | task2: ['task1', function(results, callback) { 344 | callback(); 345 | }] 346 | }, function(err) { 347 | if (err) { 348 | return done(err); 349 | } 350 | assert.ok(sync); 351 | done(); 352 | }); 353 | sync = false; 354 | }); 355 | 356 | it('auto prevent dead-locks due to inexistant dependencies', function() { 357 | 358 | var err; 359 | try { 360 | async.auto({ 361 | task1: ['noexist', function(results, callback) { 362 | callback(null, 'task1'); 363 | }] 364 | }); 365 | } catch(e) { 366 | err = e; 367 | assert.ok(e); 368 | assert(/^async.auto task `task1` has non-existent dependency/.test(e.message)); 369 | } 370 | assert.ok(err); 371 | }); 372 | 373 | it('auto prevent dead-locks due to all cyclic dependencies', function() { 374 | 375 | var err; 376 | try { 377 | async.auto({ 378 | task1: ['task2', function(results, callback) { 379 | callback(null, 'task1'); 380 | }], 381 | task2: ['task1', function(results, callback) { 382 | callback(null, 'task2'); 383 | }] 384 | }); 385 | } catch(e) { 386 | err = e; 387 | assert.ok(e); 388 | assert.strictEqual(e.message, 'async.auto task has cyclic dependencies'); 389 | } 390 | assert.ok(err); 391 | }); 392 | 393 | it('auto prevent dead-locks due to some cyclic dependencies', function() { 394 | 395 | var err; 396 | try { 397 | async.auto({ 398 | task1: ['task2', function(results, callback) { 399 | callback(null, 'task1'); 400 | }], 401 | task2: ['task1', function(results, callback) { 402 | callback(null, 'task2'); 403 | }], 404 | task3: function(callback) { 405 | callback(null, 'task3'); 406 | }, 407 | task4: ['task5', function(results, callback) { 408 | callback(null, 'task4'); 409 | }], 410 | task5: ['task4', function(results, callback) { 411 | callback(null, 'task5'); 412 | }] 413 | }); 414 | } catch(e) { 415 | err = e; 416 | assert.ok(e); 417 | assert.strictEqual(e.message, 'async.auto task has cyclic dependencies'); 418 | } 419 | assert.ok(err); 420 | }); 421 | 422 | it('should throw an error if tasks have cyclic dependencies', function() { 423 | 424 | var err; 425 | var task = function(name) { 426 | return function(results, callback) { 427 | callback(null, 'task ' + name); 428 | }; 429 | }; 430 | try { 431 | async.auto({ 432 | a: ['c', task('a')], 433 | b: ['a', task('b')], 434 | c: ['b', task('c')] 435 | }); 436 | } catch(e) { 437 | err = e; 438 | assert.ok(e); 439 | assert.strictEqual(e.message, 'async.auto task has cyclic dependencies'); 440 | } 441 | assert.ok(err); 442 | }); 443 | 444 | it('should work even if reserved name is included', function(done) { 445 | // var async = require('async'); 446 | var tasks = { 447 | one: function(next) { 448 | next(null, 1); 449 | }, 450 | hasOwnProperty: function(next) { 451 | next(null, 2); 452 | } 453 | }; 454 | async.auto(tasks, function(err, res) { 455 | if (err) { 456 | return done(err); 457 | } 458 | assert.deepStrictEqual(res, { 459 | one: 1, 460 | hasOwnProperty: 2 461 | }); 462 | done(); 463 | }); 464 | }); 465 | 466 | /** 467 | * @see https://github.com/suguru03/neo-async/issues/57 468 | */ 469 | it('should work without cyclic dependencies error', function(done) { 470 | var error = new Error('error'); 471 | async.auto({ 472 | task1: function(callback) { 473 | setTimeout(callback, delay, error); 474 | }, 475 | task2: function(callback) { 476 | setTimeout(callback, delay * 2) 477 | }, 478 | task3: ['task1', 'task2', function(callback) { 479 | setTimeout(callback, delay * 2) 480 | }] 481 | }, function(err) { 482 | assert.strictEqual(err, error); 483 | setTimeout(done, delay * 3); 484 | }); 485 | }); 486 | }); 487 | -------------------------------------------------------------------------------- /test/controlFlow/test.autoInject.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | var delay = require('../config').delay; 11 | var util = require('../util'); 12 | 13 | parallel('#autoInject', function() { 14 | 15 | it('should execute by auto injection', function(done) { 16 | 17 | var order = []; 18 | async.autoInject({ 19 | task1: function(task2, callback) { 20 | assert.strictEqual(task2, 2); 21 | setTimeout(function() { 22 | order.push('task1'); 23 | callback(null, 1); 24 | }, delay); 25 | }, 26 | task2: function(callback) { 27 | setTimeout(function() { 28 | order.push('task2'); 29 | callback(null, 2); 30 | }, delay * 2); 31 | }, 32 | task3: function(task2, callback) { 33 | assert.strictEqual(task2, 2); 34 | order.push('task3'); 35 | callback(null, 3); 36 | }, 37 | task4: function(task1, task2, callback) { 38 | assert.strictEqual(task1, 1); 39 | assert.strictEqual(task2, 2); 40 | order.push('task4'); 41 | callback(null, 4); 42 | }, 43 | task5: function(task2, callback) { 44 | assert.strictEqual(task2, 2); 45 | setTimeout(function() { 46 | order.push('task5'); 47 | callback(null, 5); 48 | }); 49 | }, 50 | task6: function(task2, callback) { 51 | assert.strictEqual(task2, 2); 52 | order.push('task6'); 53 | callback(null, 6); 54 | } 55 | }, function(err, result) { 56 | if (err) { 57 | return done(err); 58 | } 59 | assert.deepStrictEqual(result, { 60 | task1: 1, 61 | task2: 2, 62 | task3: 3, 63 | task4: 4, 64 | task5: 5, 65 | task6: 6 66 | }); 67 | assert.deepStrictEqual(order, [ 68 | 'task2', 69 | 'task3', 70 | 'task6', 71 | 'task5', 72 | 'task1', 73 | 'task4' 74 | ]); 75 | done(); 76 | }); 77 | }); 78 | 79 | it('should work with array tasks', function(done) { 80 | 81 | var order = []; 82 | async.autoInject({ 83 | task1: [function(callback) { 84 | order.push('task1'); 85 | callback(null, 1); 86 | }], 87 | task2: ['task3', function(task3, callback) { 88 | assert.strictEqual(task3, 3); 89 | order.push('task2'); 90 | callback(null, 2); 91 | }], 92 | task3: function(callback) { 93 | order.push('task3'); 94 | callback(null, 3); 95 | } 96 | }, function(err, result) { 97 | if (err) { 98 | return done(err); 99 | } 100 | assert.deepStrictEqual(result, { 101 | task1: 1, 102 | task2: 2, 103 | task3: 3 104 | }); 105 | assert.deepStrictEqual(order, [ 106 | 'task1', 107 | 'task3', 108 | 'task2' 109 | ]); 110 | done(); 111 | }); 112 | }); 113 | 114 | it('should execute tasks', function(done) { 115 | 116 | var order = []; 117 | async.autoInject({ 118 | task1: function(callback) { 119 | order.push('task1'); 120 | callback(null, 1); 121 | }, 122 | task2: ['task3', function(task3, callback) { 123 | order.push('task2'); 124 | assert.strictEqual(task3, 3); 125 | callback(null, 2); 126 | }], 127 | task2_1: ['task3', function(arg1, callback) { 128 | order.push('task2_1'); 129 | assert.strictEqual(arg1, 3); 130 | assert.ok(_.isFunction(callback)); 131 | assert.strictEqual(arguments.length, 2); 132 | callback(); 133 | }], 134 | task2_2: function(task3, callback) { 135 | order.push('task2_2'); 136 | assert.strictEqual(task3, 3); 137 | callback(); 138 | }, 139 | task2_3: ['task1', 'task3', function(arg1, arg2, callback) { 140 | order.push('task2_3'); 141 | assert.strictEqual(arg1, 1); 142 | assert.strictEqual(arg2, 3); 143 | callback(); 144 | }], 145 | task2_4: ['task3', function(arg1, callback) { 146 | order.push('task2_4'); 147 | assert.strictEqual(arg1, 3); 148 | callback(); 149 | }], 150 | task3: function (callback) { 151 | order.push('task3'); 152 | callback(null, 3); 153 | } 154 | }, function(err) { 155 | if (err) { 156 | return done(err); 157 | } 158 | assert.deepStrictEqual(order, [ 159 | 'task1', 160 | 'task3', 161 | 'task2', 162 | 'task2_1', 163 | 'task2_2', 164 | 'task2_3', 165 | 'task2_4' 166 | ]); 167 | done(); 168 | }); 169 | }); 170 | 171 | it('should execute complex tasks', function(done) { 172 | 173 | var order = []; 174 | async.autoInject({ 175 | task1: ['task3', 'task2', 'task5', 'task6', function(arg1, arg2, arg3, arg4, callback) { 176 | order.push('task1'); 177 | assert.strictEqual(arg1, 3); 178 | assert.strictEqual(arg2, 2); 179 | assert.strictEqual(arg3, 5); 180 | assert.strictEqual(arg4, 6); 181 | callback(null, 1); 182 | }], 183 | task2: function(task3, callback) { 184 | assert.strictEqual(task3, 3); 185 | order.push('task2'); 186 | callback(null, 2); 187 | }, 188 | task3: ['task5', function(arg1, callback) { 189 | assert.strictEqual(arg1, 5); 190 | order.push('task3'); 191 | callback(null, 3); 192 | }], 193 | task4: function(task1, task2, task7, callback) { 194 | assert.strictEqual(task1, 1); 195 | assert.strictEqual(task2, 2); 196 | assert.strictEqual(task7, 7); 197 | order.push('task4'); 198 | callback(null, 4); 199 | }, 200 | task5: function(callback) { 201 | setTimeout(function() { 202 | order.push('task5'); 203 | callback(null, 5); 204 | }, delay * 2); 205 | }, 206 | task6: function(task7, callback) { 207 | assert.strictEqual(task7, 7); 208 | order.push('task6'); 209 | callback(null, 6); 210 | }, 211 | task7: function(callback) { 212 | setTimeout(function() { 213 | order.push('task7'); 214 | callback(null, 7); 215 | }, delay); 216 | } 217 | }, function(err, result) { 218 | if (err) { 219 | return done(err); 220 | } 221 | assert.deepStrictEqual(result, { 222 | task1: 1, 223 | task2: 2, 224 | task3: 3, 225 | task4: 4, 226 | task5: 5, 227 | task6: 6, 228 | task7: 7 229 | }); 230 | assert.deepStrictEqual(order, [ 231 | 'task7', 232 | 'task6', 233 | 'task5', 234 | 'task3', 235 | 'task2', 236 | 'task1', 237 | 'task4' 238 | ]); 239 | done(); 240 | }); 241 | }); 242 | 243 | it('should throw an error if task argument length is zero', function() { 244 | 245 | var err; 246 | try { 247 | async.autoInject({ 248 | task1: function() { 249 | }, 250 | task2: function(task1, callback) { 251 | assert(false); 252 | callback(); 253 | } 254 | }); 255 | } catch(e) { 256 | err = e; 257 | assert.ok(e); 258 | assert.strictEqual(e.message, 'autoInject task functions require explicit parameters.'); 259 | } 260 | assert.ok(err); 261 | }); 262 | 263 | it('should throw an error if array task length is empty', function() { 264 | 265 | var err; 266 | try { 267 | async.autoInject({ 268 | task1: [], 269 | task2: function(task1, callback) { 270 | callback(); 271 | } 272 | }); 273 | } catch(e) { 274 | err = e; 275 | assert.ok(e); 276 | assert.strictEqual(e.message, 'autoInject task functions require explicit parameters.'); 277 | } 278 | assert.ok(err); 279 | }); 280 | 281 | var arrowSupport = true; 282 | try { 283 | /* jshint -W054 */ 284 | new Function('x => x'); 285 | /* jshint +W054 */ 286 | } catch (e) { 287 | arrowSupport = false; 288 | } 289 | 290 | if (arrowSupport) { 291 | // Needs to be run on ES6 only 292 | 293 | /* jshint -W061 */ 294 | eval("(function() { " + 295 | " it('should work with es6 arrow syntax', function (done) { " + 296 | " async.autoInject({ " + 297 | " task1: (cb) => cb(null, 1), " + 298 | " task2: ( task3 , cb ) => cb(null, 2), " + 299 | " task3: cb => cb(null, 3) " + 300 | " }, (err, results) => { " + 301 | " assert.deepStrictEqual(results, { " + 302 | " task1: 1, " + 303 | " task2: 2, " + 304 | " task3: 3 " + 305 | " }); " + 306 | " done(); " + 307 | " }); " + 308 | " }); " + 309 | "}) " 310 | )(); 311 | /* jshint +W061 */ 312 | } 313 | 314 | var defaultSupport = true; 315 | 316 | try { 317 | eval('function x(y = 1){ return y }'); 318 | }catch (e) { 319 | defaultSupport = false; 320 | } 321 | 322 | if(arrowSupport && defaultSupport) { 323 | // Needs to be run on ES6 only 324 | 325 | /* eslint {no-eval: 0}*/ 326 | eval("(function() { " + 327 | " it('should work with es6 obj method syntax', function (done) { " + 328 | " async.autoInject({ " + 329 | " task1 (cb) { cb(null, 1) }, " + 330 | " task2 ( task3 , cb ) { cb(null, 2) }, " + 331 | " task3 (cb) { cb(null, 3) }, " + 332 | " task4 ( task2 , cb ) { cb(null) }, " + 333 | " task5 ( task4 = 4 , cb ) { cb(null, task4 + 1) } " + 334 | " }, (err, results) => { " + 335 | " assert.strictEqual(results.task1, 1); " + 336 | " assert.strictEqual(results.task3, 3); " + 337 | " assert.strictEqual(results.task4, undefined); " + 338 | " assert.strictEqual(results.task5, 5); " + 339 | " done(); " + 340 | " }); " + 341 | " }); " + 342 | "}) " 343 | )(); 344 | } 345 | 346 | it('should avoid double callback', function(done) { 347 | 348 | var called = false; 349 | var tasks = { 350 | task1: function(callback) { 351 | try { 352 | callback('error'); 353 | } catch(exception) { 354 | try { 355 | callback(exception); 356 | } catch(e) { 357 | assert.ok(e); 358 | util.errorChecker(e); 359 | } 360 | done(); 361 | } 362 | } 363 | }; 364 | async.autoInject(tasks, function(err) { 365 | assert.ok(err); 366 | assert.strictEqual(called, false); 367 | called = true; 368 | async.nothing(); 369 | }); 370 | }); 371 | }); 372 | -------------------------------------------------------------------------------- /test/controlFlow/test.cargo.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | var delay = require('../config').delay; 11 | var util = require('../util'); 12 | 13 | parallel('#cargo', function() { 14 | 15 | it('should execute in accordance with payload', function(done) { 16 | 17 | var order = []; 18 | var delays = [4 * delay, 4 * delay, 2 * delay]; 19 | var iterator = function(tasks, callback) { 20 | setTimeout(function() { 21 | order.push('process ' + tasks.join(' ')); 22 | callback('err', 'arg'); 23 | }, delays.shift()); 24 | }; 25 | 26 | var cargo = async.cargo(iterator, 2); 27 | 28 | cargo.push(1, function(err, arg) { 29 | assert.strictEqual(err, 'err'); 30 | assert.strictEqual(arg, 'arg'); 31 | assert.strictEqual(cargo.length(), 3); 32 | order.push('callback ' + 1); 33 | }); 34 | cargo.push(2, function(err, arg) { 35 | assert.strictEqual(err, 'err'); 36 | assert.strictEqual(arg, 'arg'); 37 | assert.strictEqual(cargo.length(), 3); 38 | order.push('callback ' + 2); 39 | }); 40 | 41 | assert.strictEqual(cargo.length(), 2); 42 | 43 | setTimeout(function() { 44 | cargo.push(3, function(err, arg) { 45 | assert.strictEqual(err, 'err'); 46 | assert.strictEqual(arg, 'arg'); 47 | assert.strictEqual(cargo.length(), 1); 48 | order.push('callback ' + 3); 49 | }); 50 | }, 2 * delay); 51 | 52 | setTimeout(function() { 53 | cargo.push(4, function(err, arg) { 54 | assert.strictEqual(err, 'err'); 55 | assert.strictEqual(arg, 'arg'); 56 | assert.strictEqual(cargo.length(), 1); 57 | order.push('callback ' + 4); 58 | }); 59 | assert.strictEqual(cargo.length(), 2); 60 | cargo.push(5, function(err, arg) { 61 | assert.strictEqual(err, 'err'); 62 | assert.strictEqual(arg, 'arg'); 63 | order.push('callback ' + 5); 64 | assert.strictEqual(cargo.length(), 0); 65 | }); 66 | }, 3 * delay); 67 | 68 | setTimeout(function() { 69 | assert.deepStrictEqual(order, [ 70 | 'process 1 2', 'callback 1', 'callback 2', 71 | 'process 3 4', 'callback 3', 'callback 4', 72 | 'process 5', 'callback 5' 73 | ]); 74 | assert.strictEqual(cargo.length(), 0); 75 | done(); 76 | }, 20 * delay); 77 | }); 78 | 79 | it('should execute without callback', function(done) { 80 | 81 | var order = []; 82 | var delays = [ 83 | 4 * delay, 84 | 2 * delay, 85 | 6 * delay, 86 | 2 * delay 87 | ]; 88 | 89 | var c = async.cargo(function(tasks, callback) { 90 | setTimeout(function() { 91 | order.push('process ' + tasks.join(' ')); 92 | callback('error', 'arg'); 93 | }, delays.shift()); 94 | }, 2); 95 | 96 | c.push(1); 97 | setTimeout(function() { 98 | c.push(2); 99 | }, 3 * delay); 100 | setTimeout(function() { 101 | c.push(3); 102 | c.push(4); 103 | c.push(5); 104 | }, 4.5 * delay); 105 | 106 | setTimeout(function() { 107 | assert.deepStrictEqual(order, [ 108 | 'process 1', 109 | 'process 2', 110 | 'process 3 4', 111 | 'process 5' 112 | ]); 113 | done(); 114 | }, 20 * delay); 115 | 116 | }); 117 | 118 | it('should execute with bulk tasks', function(done) { 119 | 120 | var order = []; 121 | var delays = [3 * delay, delay]; 122 | 123 | var c = async.cargo(function(tasks, callback) { 124 | setTimeout(function() { 125 | order.push('process ' + tasks.join(' ')); 126 | callback('error', tasks.join(' ')); 127 | }, delays.shift()); 128 | }, 3); 129 | 130 | c.push([1, 2, 3, 4], function(err, arg) { 131 | assert.strictEqual(err, 'error'); 132 | order.push('callback ' + arg); 133 | }); 134 | 135 | assert.strictEqual(c.length(), 4); 136 | 137 | setTimeout(function() { 138 | assert.deepStrictEqual(order, [ 139 | 'process 1 2 3', 140 | 'callback 1 2 3', 141 | 'callback 1 2 3', 142 | 'callback 1 2 3', 143 | 'process 4', 144 | 'callback 4' 145 | ]); 146 | done(); 147 | }, 20 * delay); 148 | }); 149 | 150 | it('should execute drain once', function(done) { 151 | 152 | var order = []; 153 | var c = async.cargo(function(tasks, callback) { 154 | order.push(tasks); 155 | callback(); 156 | }, 3); 157 | 158 | var drainCounter = 0; 159 | c.drain = function() { 160 | drainCounter++; 161 | }; 162 | 163 | var n = 10; 164 | _.times(n, c.push); 165 | assert.strictEqual(c.length(), 10); 166 | 167 | setTimeout(function() { 168 | assert.deepStrictEqual(order, [ 169 | [0, 1, 2], 170 | [3, 4, 5], 171 | [6, 7, 8], 172 | [9] 173 | ]); 174 | assert.strictEqual(drainCounter, 1); 175 | done(); 176 | }, 120); 177 | 178 | }); 179 | 180 | it('should execute drain twice', function(done) { 181 | 182 | var order = []; 183 | var c = async.cargo(function(tasks, callback) { 184 | order.push(tasks); 185 | assert.ok(c.running()); 186 | callback(); 187 | }, 3); 188 | 189 | var drainCounter = 0; 190 | c.drain = function() { 191 | drainCounter++; 192 | }; 193 | var saturated = false; 194 | c.saturated = function() { 195 | saturated = true; 196 | }; 197 | 198 | var n = 10; 199 | var loadCargo = _.times.bind(_, n, c.push); 200 | loadCargo(); 201 | assert.strictEqual(c.length(), 10); 202 | 203 | var empty = false; 204 | c.empty = function() { 205 | empty = true; 206 | }; 207 | setTimeout(loadCargo, 5 * delay); 208 | 209 | setTimeout(function() { 210 | assert.deepStrictEqual(order, [ 211 | [0, 1, 2], 212 | [3, 4, 5], 213 | [6, 7, 8], 214 | [9], 215 | [0, 1, 2], 216 | [3, 4, 5], 217 | [6, 7, 8], 218 | [9] 219 | ]); 220 | assert.strictEqual(drainCounter, 2); 221 | assert.ok(saturated); 222 | assert.ok(empty); 223 | done(); 224 | }, 10 * delay); 225 | 226 | }); 227 | 228 | it('should get workers list', function(done) { 229 | 230 | var order = []; 231 | var workersList = []; 232 | var tasks = [0, 1, 2, 3, 4]; 233 | var payload = 3; 234 | var worker = function(tasks, callback) { 235 | order.push(tasks); 236 | workersList.push(_.cloneDeep(c.workersList())); 237 | callback(); 238 | }; 239 | var c = async.cargo(worker, payload); 240 | c.push(tasks); 241 | c.drain = function() { 242 | assert.deepStrictEqual(order, [ 243 | [0, 1, 2], 244 | [3, 4] 245 | ]); 246 | assert.strictEqual(workersList.length, 2); 247 | assert.strictEqual(workersList[0].length, 3); 248 | assert.strictEqual(workersList[1].length, 2); 249 | done(); 250 | }; 251 | }); 252 | 253 | it('should check events', function (done) { 254 | 255 | var calls = []; 256 | var q = async.cargo(function(task, cb) { 257 | // nop 258 | calls.push('process ' + task); 259 | async.setImmediate(cb); 260 | }, 1); 261 | q.concurrency = 3; 262 | 263 | q.saturated = function() { 264 | assert(q.running() === 3, 'cargo should be saturated now'); 265 | calls.push('saturated'); 266 | }; 267 | q.empty = function() { 268 | assert(q.length() === 0, 'cargo should be empty now'); 269 | calls.push('empty'); 270 | }; 271 | q.drain = function() { 272 | assert( 273 | q.length() === 0 && q.running() === 0, 274 | 'cargo should be empty now and no more workers should be running' 275 | ); 276 | calls.push('drain'); 277 | assert.deepStrictEqual(calls, [ 278 | 'process foo', 279 | 'process bar', 280 | 'saturated', 281 | 'process zoo', 282 | 'foo cb', 283 | 'saturated', 284 | 'process poo', 285 | 'bar cb', 286 | 'empty', 287 | 'saturated', 288 | 'process moo', 289 | 'zoo cb', 290 | 'poo cb', 291 | 'moo cb', 292 | 'drain' 293 | ]); 294 | done(); 295 | }; 296 | q.push('foo', function () {calls.push('foo cb');}); 297 | q.push('bar', function () {calls.push('bar cb');}); 298 | q.push('zoo', function () {calls.push('zoo cb');}); 299 | q.push('poo', function () {calls.push('poo cb');}); 300 | q.push('moo', function () {calls.push('moo cb');}); 301 | }); 302 | 303 | it('should avoid double callback', function(done) { 304 | 305 | var called = false; 306 | var iterator = function(task, callback) { 307 | try { 308 | callback('error'); 309 | } catch(exception) { 310 | try { 311 | callback(exception); 312 | } catch(e) { 313 | assert.ok(e); 314 | util.errorChecker(e); 315 | } 316 | done(); 317 | } 318 | }; 319 | var cargo = async.cargo(iterator); 320 | cargo.push(1, function(err) { 321 | assert.ok(err); 322 | assert.strictEqual(called, false); 323 | called = true; 324 | async.nothing(); 325 | }); 326 | }); 327 | 328 | }); 329 | -------------------------------------------------------------------------------- /test/controlFlow/test.compose.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | 10 | parallel('#compose', function() { 11 | 12 | it('should execute in order of insertion', function(done) { 13 | 14 | var add2 = function(n, cb) { 15 | assert.strictEqual(n, 3); 16 | setTimeout(function() { 17 | cb(null, n + 2); 18 | }, 50); 19 | }; 20 | 21 | var mul3 = function(n, cb) { 22 | assert.strictEqual(n, 5); 23 | setTimeout(function() { 24 | cb(null, n * 3); 25 | }, 15); 26 | }; 27 | 28 | var add1 = function(n, cb) { 29 | assert.strictEqual(n, 15); 30 | setTimeout(function() { 31 | cb(null, n + 1); 32 | }, 100); 33 | }; 34 | 35 | var add2mul3add1 = async.compose(add1, mul3, add2); 36 | 37 | add2mul3add1(3, function(err, res) { 38 | if (err) { 39 | return done(err); 40 | } 41 | assert.strictEqual(res, 16); 42 | done(); 43 | }); 44 | 45 | }); 46 | 47 | it('should execute in order of insertion with binding', function(done) { 48 | 49 | var pow2 = function(n, cb) { 50 | var self = this; 51 | assert.strictEqual(n, 3); 52 | setTimeout(function() { 53 | cb(null, self.pow(n, 2)); 54 | }, 50); 55 | }; 56 | 57 | var mul3 = function(n, cb) { 58 | assert.strictEqual(n, 9); 59 | setTimeout(function() { 60 | cb(null, n * 3); 61 | }, 15); 62 | }; 63 | 64 | var pow3 = function(n, cb) { 65 | var self = this; 66 | assert.strictEqual(n, 27); 67 | setTimeout(function() { 68 | cb(null, self.pow(n, 3)); 69 | }, 100); 70 | }; 71 | 72 | var add2mul3add1 = async.compose(pow3, mul3, pow2); 73 | 74 | add2mul3add1.call(Math, 3, function(err, res) { 75 | if (err) { 76 | return done(err); 77 | } 78 | assert.strictEqual(res, 19683); 79 | done(); 80 | }); 81 | 82 | }); 83 | 84 | it('should throw error', function(done) { 85 | 86 | var add2 = function(n, cb) { 87 | assert.strictEqual(n, 3); 88 | setTimeout(function() { 89 | cb(null, n + 2); 90 | }, 50); 91 | }; 92 | 93 | var mul3 = function(n, cb) { 94 | assert.strictEqual(n, 5); 95 | setTimeout(function() { 96 | cb(new Error('error')); 97 | }, 15); 98 | }; 99 | 100 | var add1 = function(n, cb) { 101 | setTimeout(function() { 102 | cb(null, n + 1); 103 | }, 100); 104 | }; 105 | 106 | var add2mul3add1 = async.compose(add1, mul3, add2); 107 | 108 | add2mul3add1(3, function(err) { 109 | assert.ok(err); 110 | done(); 111 | }); 112 | 113 | }); 114 | 115 | it('should execute with binding', function(done) { 116 | 117 | var testContext = { 118 | name: 'foo' 119 | }; 120 | 121 | var add2 = function(n, cb) { 122 | assert.strictEqual(this, testContext); 123 | setTimeout(function() { 124 | cb(null, n + 2); 125 | }, 50); 126 | }; 127 | 128 | var mul3 = function(n, cb) { 129 | assert.strictEqual(this, testContext); 130 | setTimeout(function() { 131 | cb(null, n * 3); 132 | }, 15); 133 | }; 134 | 135 | var add2mul3add1 = async.compose(mul3, add2); 136 | 137 | add2mul3add1.call(testContext, 3, function(err, result) { 138 | if (err) { 139 | return done(err); 140 | } 141 | assert.strictEqual(this, testContext); 142 | assert.strictEqual(result, 15); 143 | done(); 144 | }); 145 | 146 | }); 147 | 148 | }); 149 | -------------------------------------------------------------------------------- /test/controlFlow/test.during.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | 11 | parallel('#during', function() { 12 | 13 | it('should execute until asynchronous test is false', function(done) { 14 | 15 | var order = []; 16 | var count = 0; 17 | var test = function(callback) { 18 | order.push(['test', count]); 19 | callback(null, count < 5); 20 | }; 21 | var iterator = function(callback) { 22 | order.push(['iterator', count]); 23 | count++; 24 | setTimeout(function() { 25 | callback(); 26 | }, 10); 27 | }; 28 | async.during(test, iterator, function(err) { 29 | if (err) { 30 | return done(err); 31 | } 32 | assert.strictEqual(count, 5); 33 | assert.deepStrictEqual(order, [ 34 | ['test', 0], 35 | ['iterator', 0], 36 | ['test', 1], 37 | ['iterator', 1], 38 | ['test', 2], 39 | ['iterator', 2], 40 | ['test', 3], 41 | ['iterator', 3], 42 | ['test', 4], 43 | ['iterator', 4], 44 | ['test', 5] 45 | ]); 46 | done(); 47 | }); 48 | }); 49 | 50 | it('should execute without binding until asynchronous test is false', function(done) { 51 | 52 | var count = 0; 53 | var sum = 0; 54 | var test = function(callback) { 55 | callback(null, count < 5); 56 | }; 57 | var iterator = function(callback) { 58 | count++; 59 | sum += this && this.num || 3; 60 | setTimeout(function() { 61 | callback(); 62 | }, 10); 63 | }; 64 | async.during(test, iterator, function(err) { 65 | if (err) { 66 | return done(err); 67 | } 68 | assert.strictEqual(count, 5); 69 | assert.strictEqual(sum, 15); 70 | done(); 71 | }, { 72 | num: 2 73 | }); 74 | }); 75 | 76 | it('should throw error if error occurs in test', function(done) { 77 | 78 | var count = 0; 79 | var test = function(callback) { 80 | callback(new Error('error')); 81 | }; 82 | var iterator = function(callback) { 83 | count++; 84 | callback(); 85 | }; 86 | async.during(test, iterator, function(err) { 87 | assert.ok(err); 88 | assert.strictEqual(count, 0); 89 | done(); 90 | }); 91 | }); 92 | 93 | it('should throw error if error occurs in iterator', function(done) { 94 | 95 | var count = 0; 96 | var test = function(callback) { 97 | callback(null, count < 5); 98 | }; 99 | var iterator = function(callback) { 100 | count++; 101 | callback(new Error('error')); 102 | }; 103 | async.during(test, iterator, function(err) { 104 | assert.ok(err); 105 | assert.strictEqual(count, 1); 106 | done(); 107 | }); 108 | }); 109 | 110 | }); 111 | 112 | parallel('#doDuring', function() { 113 | 114 | it('should execute until asynchronous test is false', function(done) { 115 | 116 | var order = []; 117 | var count = 0; 118 | var test = function(callback) { 119 | order.push(['test', count]); 120 | callback(null, count < 5); 121 | }; 122 | var iterator = function(callback) { 123 | order.push(['iterator', count]); 124 | count++; 125 | setTimeout(function() { 126 | callback(); 127 | }, 10); 128 | }; 129 | async.doDuring(iterator, test, function(err) { 130 | if (err) { 131 | return done(err); 132 | } 133 | assert.strictEqual(count, 5); 134 | assert.deepStrictEqual(order, [ 135 | ['iterator', 0], 136 | ['test', 1], 137 | ['iterator', 1], 138 | ['test', 2], 139 | ['iterator', 2], 140 | ['test', 3], 141 | ['iterator', 3], 142 | ['test', 4], 143 | ['iterator', 4], 144 | ['test', 5] 145 | ]); 146 | done(); 147 | }); 148 | }); 149 | 150 | it('should execute with binding until asynchronous test is false', function(done) { 151 | 152 | var order = []; 153 | var count = 0; 154 | var sum = 0; 155 | var test = function(callback) { 156 | order.push(['test', count]); 157 | callback(null, count < 5); 158 | }; 159 | var iterator = function(callback) { 160 | order.push(['iterator', count]); 161 | count++; 162 | sum += this && this.num || 3; 163 | setTimeout(function() { 164 | callback(); 165 | }, 10); 166 | }; 167 | async.doDuring(iterator, test, function(err) { 168 | if (err) { 169 | return done(err); 170 | } 171 | assert.strictEqual(count, 5); 172 | assert.strictEqual(sum, 15); 173 | assert.deepStrictEqual(order, [ 174 | ['iterator', 0], 175 | ['test', 1], 176 | ['iterator', 1], 177 | ['test', 2], 178 | ['iterator', 2], 179 | ['test', 3], 180 | ['iterator', 3], 181 | ['test', 4], 182 | ['iterator', 4], 183 | ['test', 5] 184 | ]); 185 | done(); 186 | }, { 187 | num: 2 188 | }); 189 | }); 190 | 191 | it('should execute with some arguments', function(done) { 192 | 193 | var order = []; 194 | var count = 0; 195 | var test = function() { 196 | order.push(['test', count]); 197 | if (count % 2) { 198 | assert.strictEqual(arguments.length, 2); 199 | } else { 200 | assert.strictEqual(arguments.length, 3); 201 | } 202 | var callback = _.slice(arguments).pop(); 203 | callback(null, count < 5); 204 | }; 205 | var iterator = function(callback) { 206 | order.push(['iterator', count]); 207 | count++; 208 | setTimeout(function() { 209 | if (count % 2) { 210 | callback(null, 1); 211 | } else { 212 | callback(null, 1, 2); 213 | } 214 | }, 10); 215 | }; 216 | async.doDuring(iterator, test, function(err) { 217 | if (err) { 218 | return done(err); 219 | } 220 | assert.deepStrictEqual(order, [ 221 | ['iterator', 0], 222 | ['test', 1], 223 | ['iterator', 1], 224 | ['test', 2], 225 | ['iterator', 2], 226 | ['test', 3], 227 | ['iterator', 3], 228 | ['test', 4], 229 | ['iterator', 4], 230 | ['test', 5] 231 | ]); 232 | done(); 233 | }); 234 | }); 235 | 236 | it('should throw error if error occurs in test', function(done) { 237 | 238 | var count = 0; 239 | var test = function(callback) { 240 | callback(new Error('error')); 241 | }; 242 | var iterator = function(callback) { 243 | count++; 244 | callback(); 245 | }; 246 | async.doDuring(iterator, test, function(err) { 247 | assert.ok(err); 248 | assert.strictEqual(count, 1); 249 | done(); 250 | }); 251 | }); 252 | 253 | it('should throw error if error occurs in iterator', function(done) { 254 | 255 | var count = 0; 256 | var test = function(callback) { 257 | callback(null, count < 5); 258 | }; 259 | var iterator = function(callback) { 260 | count++; 261 | callback(new Error('error')); 262 | }; 263 | async.doDuring(iterator, test, function(err) { 264 | assert.ok(err); 265 | assert.strictEqual(count, 1); 266 | done(); 267 | }); 268 | }); 269 | 270 | }); 271 | -------------------------------------------------------------------------------- /test/controlFlow/test.forever.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | 11 | parallel('#forever', function() { 12 | 13 | it('should execute until error occurs', function(done) { 14 | 15 | var count = 0; 16 | var limit = 5; 17 | var order = []; 18 | var iterator = function(callback) { 19 | order.push(count++); 20 | if (count === limit) { 21 | return callback(new Error('end')); 22 | } 23 | callback(); 24 | }; 25 | 26 | async.forever(iterator, function(err) { 27 | assert.ok(err); 28 | assert.deepStrictEqual(order, [0, 1, 2, 3, 4]); 29 | done(); 30 | }); 31 | }); 32 | 33 | it('should execute without binding until error occurs', function(done) { 34 | 35 | var count = 0; 36 | var limit = 5; 37 | var order = []; 38 | var result = []; 39 | var iterator = function(callback) { 40 | assert.strictEqual(this, undefined); 41 | result.push(count * count); 42 | order.push(count++); 43 | if (count === limit) { 44 | return callback(new Error('end')); 45 | } 46 | callback(); 47 | }; 48 | 49 | async.forever(iterator, function(err) { 50 | assert.ok(err); 51 | assert.deepStrictEqual(order, [0, 1, 2, 3, 4]); 52 | assert.deepStrictEqual(result, [0, 1, 4, 9, 16]); 53 | done(); 54 | }, Math); 55 | }); 56 | 57 | it('should execute on asynchronous', function(done) { 58 | 59 | var sync = true; 60 | var count = 0; 61 | var limit = 5; 62 | var iterator = function(callback) { 63 | if (count++ === limit) { 64 | return callback(new Error('end')); 65 | } 66 | callback(); 67 | }; 68 | async.forever(iterator, function(err) { 69 | assert.ok(err); 70 | assert.strictEqual(sync, false); 71 | done(); 72 | }); 73 | sync = false; 74 | }); 75 | 76 | it('should throw error', function(done) { 77 | 78 | var count = 0; 79 | var limit = 5; 80 | var order = []; 81 | var iterator = function(callback) { 82 | order.push(count++); 83 | if (count === limit) { 84 | return callback(new Error('end')); 85 | } 86 | callback(); 87 | }; 88 | domain.create() 89 | .on('error', function(err) { 90 | assert.strictEqual(err.message, 'end'); 91 | assert.deepStrictEqual(order, [0, 1, 2, 3, 4]); 92 | done(); 93 | }) 94 | .run(function() { 95 | async.forever(iterator); 96 | }); 97 | }); 98 | 99 | }); 100 | -------------------------------------------------------------------------------- /test/controlFlow/test.iterator.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | 10 | parallel('#iterator', function() { 11 | 12 | it('should execute iterators', function(done) { 13 | 14 | var order = []; 15 | var iterator = async.iterator([ 16 | function() { 17 | order.push(1); 18 | }, 19 | function(arg1) { 20 | assert.strictEqual(arg1, 'arg1'); 21 | order.push(2); 22 | }, 23 | function(arg1, arg2) { 24 | assert.strictEqual(arg1, 'arg1'); 25 | assert.strictEqual(arg2, 'arg2'); 26 | order.push(3); 27 | } 28 | ]); 29 | 30 | iterator(); 31 | assert.deepStrictEqual(order, [1]); 32 | var iterator2 = iterator(); 33 | assert.deepStrictEqual(order, [1, 1]); 34 | var iterator3 = iterator2('arg1'); 35 | assert.deepStrictEqual(order, [1, 1, 2]); 36 | var iterator4 = iterator3('arg1', 'arg2'); 37 | assert.deepStrictEqual(order, [1, 1, 2, 3]); 38 | assert.strictEqual(iterator4, null); 39 | done(); 40 | }); 41 | 42 | it('should execute object iterators', function(done) { 43 | 44 | var order = []; 45 | var iterator = async.iterator({ 46 | a: function() { 47 | order.push(1); 48 | }, 49 | b: function(arg1) { 50 | assert.strictEqual(arg1, 'arg1'); 51 | order.push(2); 52 | }, 53 | c: function(arg1, arg2) { 54 | assert.strictEqual(arg1, 'arg1'); 55 | assert.strictEqual(arg2, 'arg2'); 56 | order.push(3); 57 | } 58 | }); 59 | 60 | iterator(); 61 | assert.deepStrictEqual(order, [1]); 62 | var iterator2 = iterator(); 63 | assert.deepStrictEqual(order, [1, 1]); 64 | var iterator3 = iterator2('arg1'); 65 | assert.deepStrictEqual(order, [1, 1, 2]); 66 | var iterator4 = iterator3('arg1', 'arg2'); 67 | assert.deepStrictEqual(order, [1, 1, 2, 3]); 68 | assert.strictEqual(iterator4, null); 69 | done(); 70 | 71 | }); 72 | 73 | it('should get undefined if array is empty', function(done) { 74 | 75 | var iterator = async.iterator([]); 76 | assert.deepStrictEqual(iterator(), null); 77 | assert.deepStrictEqual(iterator.next(), null); 78 | done(); 79 | }); 80 | 81 | it('should get next iterator', function(done) { 82 | 83 | var order = []; 84 | var iterator = async.iterator([ 85 | function() { 86 | order.push(1); 87 | }, 88 | function(arg1) { 89 | assert.strictEqual(arg1, 'arg1'); 90 | order.push(2); 91 | }, 92 | function(arg1, arg2) { 93 | assert.strictEqual(arg1, 'arg1'); 94 | assert.strictEqual(arg2, 'arg2'); 95 | order.push(3); 96 | } 97 | ]); 98 | 99 | var fn = iterator.next(); 100 | var iterator2 = fn('arg1'); 101 | assert.deepStrictEqual(order, [2]); 102 | iterator2('arg1', 'arg2'); 103 | assert.deepStrictEqual(order, [2, 3]); 104 | assert.deepStrictEqual(iterator2.next(), null); 105 | done(); 106 | }); 107 | 108 | }); 109 | -------------------------------------------------------------------------------- /test/controlFlow/test.parallel.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var _ = require('lodash'); 8 | var parallel = require('mocha.parallel'); 9 | 10 | var async = global.async || require('../../'); 11 | var delay = require('../config').delay; 12 | var util = require('../util'); 13 | 14 | function createTasks(order, numbers) { 15 | 16 | return _.transform(numbers, function(memo, num, index) { 17 | 18 | memo[index] = function(callback) { 19 | var self = this; 20 | setTimeout(function() { 21 | order.push(num); 22 | if (self && self.round) { 23 | num = self.round(num); 24 | } 25 | callback(null, num * 2); 26 | }, num * delay); 27 | }; 28 | }); 29 | } 30 | 31 | parallel('#parallel', function() { 32 | 33 | it('should execute in parallel by tasks of array', function(done) { 34 | 35 | var order = []; 36 | var numbers = [1, 3, 2, 4]; 37 | var tasks = createTasks(order, numbers); 38 | tasks.push(function(cb) { 39 | setTimeout(function() { 40 | order.push(5); 41 | cb(null, 5, 5); 42 | }, delay * 5); 43 | }); 44 | 45 | async.parallel(tasks, function(err, res) { 46 | if (err) { 47 | return done(err); 48 | } 49 | assert.deepStrictEqual(res, [2, 6, 4, 8, [5, 5]]); 50 | assert.deepStrictEqual(order, [1, 2, 3, 4, 5]); 51 | done(); 52 | }); 53 | }); 54 | 55 | it('should execute in parallel by tasks of object', function(done) { 56 | 57 | var order = []; 58 | var numbers = { 59 | a: 4, 60 | b: 2, 61 | c: 1, 62 | d: 3 63 | }; 64 | var tasks = createTasks(order, numbers); 65 | 66 | async.parallel(tasks, function(err, res) { 67 | if (err) { 68 | return done(err); 69 | } 70 | assert.deepStrictEqual(res, { 71 | c: 2, 72 | b: 4, 73 | d: 6, 74 | a: 8 75 | }); 76 | assert.deepStrictEqual(order, [1, 2, 3, 4]); 77 | done(); 78 | }); 79 | }); 80 | 81 | it('should execute in parallel by tasks of array without binding', function(done) { 82 | 83 | var order = []; 84 | var numbers = [1.2, 2.4, 1.5, 3.6]; 85 | var tasks = createTasks(order, numbers); 86 | 87 | async.parallel(tasks, function(err, res) { 88 | if (err) { 89 | return done(err); 90 | } 91 | assert.deepStrictEqual(res, [2.4, 4.8, 3, 7.2]); 92 | assert.deepStrictEqual(order, [1.2, 1.5, 2.4, 3.6]); 93 | done(); 94 | }, Math); 95 | }); 96 | 97 | it('should execute in parallel by tasks of object without binding', function(done) { 98 | 99 | var order = []; 100 | var numbers = { 101 | a: 1.2, 102 | b: 2.4, 103 | c: 1.5, 104 | d: 3.6 105 | }; 106 | var tasks = createTasks(order, numbers); 107 | 108 | async.parallel(tasks, function(err, res) { 109 | if (err) { 110 | return done(err); 111 | } 112 | assert.deepStrictEqual(res, { 113 | a: 2.4, 114 | c: 3, 115 | b: 4.8, 116 | d: 7.2 117 | }); 118 | assert.deepStrictEqual(order, [1.2, 1.5, 2.4, 3.6]); 119 | done(); 120 | }, Math); 121 | }); 122 | 123 | it('should return response immediately if array task is empty', function(done) { 124 | 125 | var tasks = []; 126 | async.parallel(tasks, function(err, res) { 127 | if (err) { 128 | return done(err); 129 | } 130 | assert.deepStrictEqual(res, []); 131 | done(); 132 | }); 133 | }); 134 | 135 | it('should return response immediately if object task is empty', function(done) { 136 | 137 | var tasks = {}; 138 | async.parallel(tasks, function(err, res) { 139 | if (err) { 140 | return done(err); 141 | } 142 | assert.deepStrictEqual(res, {}); 143 | done(); 144 | }); 145 | }); 146 | 147 | it('should return response immediately if task is not collection', function(done) { 148 | 149 | async.parallel(null, function(err, res) { 150 | if (err) { 151 | return done(err); 152 | } 153 | assert.strictEqual(res, undefined); 154 | done(); 155 | }); 156 | }); 157 | 158 | it('should throw error', function(done) { 159 | 160 | var order = []; 161 | var numbers = [1, 3, 2, 4]; 162 | var tasks = createTasks(order, numbers); 163 | var error = function(callback) { 164 | setTimeout(function() { 165 | callback('error'); 166 | }, delay * 2.5); 167 | }; 168 | tasks.splice(2, 0, error); 169 | 170 | async.parallel(tasks, function(err) { 171 | assert.ok(err); 172 | assert.deepStrictEqual(order, [1, 2]); 173 | done(); 174 | }); 175 | 176 | }); 177 | 178 | it('should throw error if double callback', function(done) { 179 | 180 | var errorCallCount = 0; 181 | setTimeout(function() { 182 | assert.strictEqual(errorCallCount, 1); 183 | done(); 184 | }, delay); 185 | 186 | domain.create() 187 | .on('error', util.errorChecker) 188 | .on('error', function() { 189 | errorCallCount++; 190 | }) 191 | .run(function() { 192 | var tasks = [function(next) { 193 | process.nextTick(next); 194 | process.nextTick(next); 195 | }]; 196 | async.parallel(tasks); 197 | }); 198 | }); 199 | 200 | it('should throw error only once', function(done) { 201 | 202 | var error = function(callback) { 203 | setTimeout(function() { 204 | callback('error'); 205 | }, delay); 206 | }; 207 | var called = false; 208 | var tasks = [error, error, error, error]; 209 | async.parallel(tasks, function(err) { 210 | assert.ok(err); 211 | assert.strictEqual(called, false); 212 | called = true; 213 | setTimeout(done, delay * 2); 214 | }); 215 | }); 216 | 217 | it('should avoid double callback', function(done) { 218 | 219 | var called = false; 220 | var tasks = _.times(3, function(n) { 221 | return function(callback) { 222 | try { 223 | callback('error' + n); 224 | } catch (exception) { 225 | try { 226 | callback(exception); 227 | } catch(e) { 228 | assert.ok(e); 229 | util.errorChecker(e); 230 | } 231 | done(); 232 | } 233 | }; 234 | }); 235 | async.parallel(tasks, function(err) { 236 | assert.ok(err); 237 | assert.strictEqual(called, false); 238 | called = true; 239 | async.nothing(); 240 | }); 241 | }); 242 | 243 | }); 244 | 245 | parallel('#parallelLimit', function() { 246 | 247 | it('should execute in limited by tasks of array', function(done) { 248 | 249 | var order = []; 250 | var numbers = [1, 4, 2, 3, 1]; 251 | var tasks = createTasks(order, numbers); 252 | tasks.push(function(cb) { 253 | setTimeout(function() { 254 | order.push(5); 255 | cb(null, 5, 5); 256 | }, delay * 1.5); 257 | }); 258 | 259 | async.parallelLimit(tasks, 2, function(err, res) { 260 | if (err) { 261 | return done(err); 262 | } 263 | assert.deepStrictEqual(res, [2, 8, 4, 6, 2, [5, 5]]); 264 | assert.deepStrictEqual(order, [1, 2, 4, 1, 3, 5]); 265 | done(); 266 | }); 267 | }); 268 | 269 | it('should execute in limited by tasks of object', function(done) { 270 | 271 | var order = []; 272 | var numbers = { 273 | a: 4, 274 | b: 2, 275 | c: 1, 276 | d: 3, 277 | e: 1 278 | }; 279 | var tasks = createTasks(order, numbers); 280 | 281 | async.parallelLimit(tasks, 2, function(err, res) { 282 | if (err) { 283 | return done(err); 284 | } 285 | assert.deepStrictEqual(res, { 286 | b: 4, 287 | a: 8, 288 | c: 2, 289 | d: 6, 290 | e: 2 291 | }); 292 | assert.deepStrictEqual(order, [2, 1, 4, 1, 3]); 293 | done(); 294 | }); 295 | }); 296 | 297 | it('should execute in parallel by tasks of array without binding', function(done) { 298 | 299 | var order = []; 300 | var numbers = [1.2, 2.4, 1.5, 3.6]; 301 | var tasks = createTasks(order, numbers); 302 | 303 | async.parallelLimit(tasks, 3, function(err, res) { 304 | if (err) { 305 | return done(err); 306 | } 307 | assert.deepStrictEqual(res, [2.4, 4.8, 3, 7.2]); 308 | assert.deepStrictEqual(order, [1.2, 1.5, 2.4, 3.6]); 309 | done(); 310 | }, Math); 311 | }); 312 | 313 | it('should execute in parallel by tasks of object without binding', function(done) { 314 | 315 | var order = []; 316 | var numbers = { 317 | a: 1.2, 318 | b: 2.4, 319 | c: 1.5, 320 | d: 3.6 321 | }; 322 | var tasks = createTasks(order, numbers); 323 | 324 | async.parallelLimit(tasks, 3, function(err, res) { 325 | if (err) { 326 | return done(err); 327 | } 328 | assert.deepStrictEqual(res, { 329 | a: 2.4, 330 | c: 3, 331 | b: 4.8, 332 | d: 7.2 333 | }); 334 | assert.deepStrictEqual(order, [1.2, 1.5, 2.4, 3.6]); 335 | done(); 336 | }, Math); 337 | }); 338 | 339 | it('should execute on asynchronous', function(done) { 340 | 341 | var sync = true; 342 | var numbers = { 343 | a: 4, 344 | b: 2, 345 | c: 1, 346 | d: 3, 347 | e: 1 348 | }; 349 | var tasks = _.mapValues(numbers, function(value) { 350 | return function(done) { 351 | done(null, value * 2); 352 | }; 353 | }); 354 | 355 | async.parallelLimit(tasks, 2, function(err, res) { 356 | if (err) { 357 | return done(err); 358 | } 359 | assert.strictEqual(sync, false); 360 | assert.deepStrictEqual(res, { 361 | b: 4, 362 | a: 8, 363 | c: 2, 364 | d: 6, 365 | e: 2 366 | }); 367 | done(); 368 | }); 369 | sync = false; 370 | }); 371 | 372 | it('should return response immediately if array task is empty', function(done) { 373 | 374 | var tasks = []; 375 | async.parallelLimit(tasks, 2, function(err, res) { 376 | if (err) { 377 | return done(err); 378 | } 379 | assert.deepStrictEqual(res, []); 380 | done(); 381 | }); 382 | 383 | }); 384 | 385 | it('should return response immediately if object task is empty', function(done) { 386 | 387 | var tasks = {}; 388 | async.parallelLimit(tasks, 2, function(err, res) { 389 | if (err) { 390 | return done(err); 391 | } 392 | assert.deepStrictEqual(res, {}); 393 | done(); 394 | }); 395 | 396 | }); 397 | 398 | it('should return response immediately if task is not collection', function(done) { 399 | 400 | async.parallelLimit(null, 2, function(err, res) { 401 | if (err) { 402 | return done(err); 403 | } 404 | assert.strictEqual(res, undefined); 405 | done(); 406 | }); 407 | 408 | }); 409 | 410 | it('should throw error', function(done) { 411 | 412 | var order = []; 413 | var numbers = [1, 3, 2, 4]; 414 | var tasks = createTasks(order, numbers); 415 | var error = function(callback) { 416 | setTimeout(function() { 417 | callback('error'); 418 | }, delay * 2.5); 419 | }; 420 | tasks.splice(2, 0, error); 421 | 422 | async.parallelLimit(tasks, 2, function(err) { 423 | assert.ok(err); 424 | assert.deepStrictEqual(order, [1, 3]); 425 | done(); 426 | }); 427 | 428 | }); 429 | 430 | it('should throw error if double callback', function(done) { 431 | 432 | var errorCallCount = 0; 433 | setTimeout(function() { 434 | assert.strictEqual(errorCallCount, 1); 435 | done(); 436 | }, delay); 437 | 438 | domain.create() 439 | .on('error', util.errorChecker) 440 | .on('error', function() { 441 | errorCallCount++; 442 | }) 443 | .run(function() { 444 | var tasks = [function(next) { 445 | process.nextTick(next); 446 | process.nextTick(next); 447 | }]; 448 | async.parallelLimit(tasks, 4); 449 | }); 450 | }); 451 | 452 | it('should avoid double callback', function(done) { 453 | 454 | var called = false; 455 | var tasks = _.times(3, function(n) { 456 | return function(callback) { 457 | try { 458 | callback('error' + n); 459 | } catch (exception) { 460 | try { 461 | callback(exception); 462 | } catch(e) { 463 | assert.ok(e); 464 | util.errorChecker(e); 465 | } 466 | done(); 467 | } 468 | }; 469 | }); 470 | async.parallelLimit(tasks, 2, function(err) { 471 | assert.ok(err); 472 | assert.strictEqual(called, false); 473 | called = true; 474 | async.nothing(); 475 | }); 476 | }); 477 | 478 | }); 479 | -------------------------------------------------------------------------------- /test/controlFlow/test.race.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | 11 | parallel('#race', function() { 12 | 13 | it('should call each funciton in parallel and callback with first result', function(done) { 14 | 15 | var called = 0; 16 | var tasks = _.times(10, function(index) { 17 | return function(next) { 18 | called++; 19 | next(null, index); 20 | }; 21 | }); 22 | async.race(tasks, function(err, res) { 23 | if (err) { 24 | return done(err); 25 | } 26 | assert.strictEqual(res, 0); 27 | assert.strictEqual(called, 1); 28 | setImmediate(function() { 29 | assert.strictEqual(called, 10); 30 | done(); 31 | }); 32 | }); 33 | }); 34 | 35 | it('should callback funciton in parallel with object tasks', function(done) { 36 | 37 | var called = 0; 38 | var tasks = _.mapValues(_.times(5, function(index) { 39 | return function(next) { 40 | setTimeout(function() { 41 | called++; 42 | next(null, index); 43 | }, 50 - index * 5); 44 | }; 45 | })); 46 | async.race(tasks, function(err, res) { 47 | if (err) { 48 | return done(err); 49 | } 50 | assert.strictEqual(res, 4); 51 | }); 52 | setTimeout(function() { 53 | assert.strictEqual(called, 5); 54 | done(); 55 | }, 100); 56 | }); 57 | 58 | it('should callback with the first error', function(done) { 59 | 60 | var tasks = _.times(6, function(index) { 61 | return function(next) { 62 | setTimeout(function() { 63 | next(new Error('error:' + index), index); 64 | }, 50 - index * 5); 65 | }; 66 | }); 67 | async.race(tasks, function(err, res) { 68 | assert.ok(err); 69 | assert.strictEqual(res, 5); 70 | assert.strictEqual(err.message, 'error:5'); 71 | done(); 72 | }); 73 | }); 74 | 75 | it('should callback when task is empty', function(done) { 76 | 77 | async.race([], function(err, res) { 78 | if (err) { 79 | return done(err); 80 | } 81 | assert.strictEqual(res, undefined); 82 | done(); 83 | }); 84 | }); 85 | 86 | it('should return TypeError if first argument is not an array or an object', function(done) { 87 | 88 | async.race(null, function(err, res) { 89 | assert.ok(err); 90 | assert.ok(err instanceof TypeError); 91 | assert.strictEqual(res, undefined); 92 | done(); 93 | }); 94 | }); 95 | 96 | }); 97 | -------------------------------------------------------------------------------- /test/controlFlow/test.retry.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | var delay = require('../config').delay; 10 | 11 | parallel('#retry', function() { 12 | 13 | it('should retry until response', function(done) { 14 | 15 | var failed = 3; 16 | var callCount = 0; 17 | var message = 'success'; 18 | var fn = function(callback) { 19 | callCount++; 20 | failed--; 21 | if (failed === 0) { 22 | return callback(null, message); 23 | } 24 | callback('err'); 25 | }; 26 | 27 | async.retry(fn, function(err, res) { 28 | if (err) { 29 | return done(err); 30 | } 31 | assert.strictEqual(callCount, 3); 32 | assert.strictEqual(res, message); 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should retry until time out', function(done) { 38 | 39 | var times = 3; 40 | var callCount = 0; 41 | var error = 'error'; 42 | var success = 'success'; 43 | var fn = function(callback) { 44 | callCount++; 45 | callback(error + callCount, success + callCount); 46 | }; 47 | 48 | async.retry(times, fn, function(err, res) { 49 | assert.strictEqual(callCount, 3); 50 | assert.strictEqual(err, error + times); 51 | assert.strictEqual(res, success + times); 52 | done(); 53 | }); 54 | }); 55 | 56 | it('should not require a callback', function(done) { 57 | 58 | var times = 3; 59 | var callCount = 0; 60 | var fn = function(callback) { 61 | callCount++; 62 | callback(); 63 | }; 64 | async.retry(times, fn); 65 | setTimeout(function() { 66 | assert.strictEqual(callCount, 1); 67 | done(); 68 | }, delay); 69 | }); 70 | 71 | it('should execute even if type of times is string', function(done) { 72 | 73 | var times = '3'; 74 | var callCount = 0; 75 | var fn = function(callback) { 76 | callCount++; 77 | callback(); 78 | }; 79 | async.retry(times, fn); 80 | setTimeout(function() { 81 | assert.strictEqual(callCount, 1); 82 | done(); 83 | }, delay); 84 | }); 85 | 86 | it('should throw error if arguments are empty', function() { 87 | 88 | try { 89 | async.retry(); 90 | } catch(e) { 91 | assert.ok(e); 92 | assert.strictEqual(e.message, 'Invalid arguments for async.retry'); 93 | } 94 | }); 95 | 96 | it('should throw error if first argument is not function', function() { 97 | 98 | try { 99 | async.retry(1); 100 | } catch(e) { 101 | assert.ok(e); 102 | assert.strictEqual(e.message, 'Invalid arguments for async.retry'); 103 | } 104 | }); 105 | 106 | it('should throw error if arguments are invalid', function() { 107 | 108 | try { 109 | async.retry(function() {}, 2, function() {}); 110 | } catch(e) { 111 | assert.ok(e); 112 | assert.strictEqual(e.message, 'Invalid arguments for async.retry'); 113 | } 114 | }); 115 | 116 | it('should retry with interval when all attempts succeeds', function(done) { 117 | 118 | var times = 3; 119 | var interval = delay * 3; 120 | var callCount = 0; 121 | var error = 'ERROR'; 122 | var erroredResult = 'RESULT'; 123 | var fn = function(callback) { 124 | callCount++; 125 | callback(error + callCount, erroredResult + callCount); 126 | }; 127 | var opts = { 128 | times: times, 129 | interval: interval 130 | }; 131 | var start = Date.now(); 132 | async.retry(opts, fn, function(err, res) { 133 | var diff = Date.now() - start; 134 | assert(diff >= (interval * (times - 1))); 135 | assert.strictEqual(callCount, 3); 136 | assert.strictEqual(err, error + times); 137 | assert.strictEqual(res, erroredResult + times); 138 | done(); 139 | }); 140 | }); 141 | 142 | it('should retry with empty options', function(done) { 143 | 144 | var callCount = 0; 145 | var fn = function(callback) { 146 | callCount++; 147 | callback('error'); 148 | }; 149 | var opts = {}; 150 | async.retry(opts, fn, function(err) { 151 | assert.ok(err); 152 | assert.strictEqual(callCount, 5); 153 | done(); 154 | }); 155 | }); 156 | 157 | it('should use default times', function(done) { 158 | 159 | var called = 0; 160 | async.retry(function(callback) { 161 | called++; 162 | callback('error'); 163 | }); 164 | setTimeout(function() { 165 | assert.strictEqual(called, 5); 166 | done(); 167 | }, delay); 168 | }); 169 | 170 | it('retry with custom interval when all attempts fail',function(done) { 171 | var times = 3; 172 | var intervalFunc = function(retryCount) { 173 | return retryCount * 110; 174 | }; 175 | var callCount = 0; 176 | var error = 'ERROR'; 177 | var erroredResult = 'RESULT'; 178 | var iterator = function(callback) { 179 | callCount++; 180 | callback(error + callCount, erroredResult + callCount); // respond with indexed values 181 | }; 182 | var opts = { 183 | times: times, 184 | interval: intervalFunc 185 | }; 186 | var start = Date.now(); 187 | async.retry(opts, iterator, function(err, res) { 188 | var now = Date.now(); 189 | var diff = now - start; 190 | assert.ok(diff >= 300, diff); 191 | assert.strictEqual(callCount, 3); 192 | assert.strictEqual(err, error + times); 193 | assert.strictEqual(res, erroredResult + times); 194 | done(); 195 | }); 196 | }); 197 | 198 | it('should return extra arguments', function(done) { 199 | var func = function(callback) { 200 | callback(null, 1, 2, 3); 201 | }; 202 | async.retry(5, func, function(err, arg1, arg2, arg3) { 203 | if (err) { 204 | return done(err); 205 | } 206 | assert.strictEqual(arguments.length, 4); 207 | assert.strictEqual(arg1, 1); 208 | assert.strictEqual(arg2, 2); 209 | assert.strictEqual(arg3, 3); 210 | done(); 211 | }); 212 | }); 213 | 214 | it('should return extra arguments with options', function(done) { 215 | var func = function(callback) { 216 | callback(null, 1, 2, 3); 217 | }; 218 | var intervalFunc = function(retryCount) { 219 | return retryCount * 110; 220 | }; 221 | var opts = { 222 | times: 5, 223 | interval: intervalFunc 224 | }; 225 | async.retry(opts, func, function(err, arg1, arg2, arg3) { 226 | if (err) { 227 | return done(err); 228 | } 229 | assert.strictEqual(arguments.length, 4); 230 | assert.strictEqual(arg1, 1); 231 | assert.strictEqual(arg2, 2); 232 | assert.strictEqual(arg3, 3); 233 | done(); 234 | }); 235 | }); 236 | 237 | it('should use default interval if interval is invalid string or number', function(done) { 238 | var callCount = 0; 239 | var func = function(callback) { 240 | callback(++callCount % 2, callCount); 241 | }; 242 | var opts = { 243 | interval: 'test' 244 | }; 245 | async.retry(opts, func, function(err, res) { 246 | if (err) { 247 | return done(err); 248 | } 249 | assert.strictEqual(res, 2); 250 | assert.strictEqual(callCount, 2); 251 | done(); 252 | }); 253 | }); 254 | 255 | it('retry when some attempts fail and error test returns false at some invokation',function(done) { 256 | var callCount = 0; 257 | var error = 'ERROR'; 258 | var special = 'SPECIAL_ERROR'; 259 | var erroredResult = 'RESULT'; 260 | function fn(callback) { 261 | callCount++; 262 | var err = callCount === 2 ? special : error + callCount; 263 | callback(err, erroredResult + callCount); 264 | } 265 | function errorTest(err) { 266 | return err && err === error + callCount; // just a different pattern 267 | } 268 | var options = { 269 | errorFilter: errorTest 270 | }; 271 | async.retry(options, fn, function(err, result) { 272 | assert.equal(callCount, 2, 'did not retry the correct number of times'); 273 | assert.equal(err, special, 'Incorrect error was returned'); 274 | assert.equal(result, erroredResult + 2, 'Incorrect result was returned'); 275 | done(); 276 | }); 277 | }); 278 | 279 | it('retry with interval when some attempts fail and error test returns false at some invokation',function(done) { 280 | var interval = 50; 281 | var callCount = 0; 282 | var error = 'ERROR'; 283 | var erroredResult = 'RESULT'; 284 | var special = 'SPECIAL_ERROR'; 285 | var specialCount = 3; 286 | function fn(callback) { 287 | callCount++; 288 | var err = callCount === specialCount ? special : error + callCount; 289 | callback(err, erroredResult + callCount); 290 | } 291 | function errorTest(err) { 292 | return err && err !== special; 293 | } 294 | var start = new Date().getTime(); 295 | async.retry({ interval: interval, errorFilter: errorTest }, fn, function(err, result){ 296 | var now = new Date().getTime(); 297 | var duration = now - start; 298 | assert(duration >= (interval * (specialCount - 1)), 'did not include interval'); 299 | assert.equal(callCount, specialCount, 'did not retry the correct number of times'); 300 | assert.equal(err, special, 'Incorrect error was returned'); 301 | assert.equal(result, erroredResult + specialCount, 'Incorrect result was returned'); 302 | done(); 303 | }); 304 | }); 305 | 306 | }); 307 | -------------------------------------------------------------------------------- /test/controlFlow/test.retryable.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | var delay = require('../config').delay; 10 | 11 | parallel('#retryable', function() { 12 | 13 | it('should retry', function(done) { 14 | 15 | var callCount = 0; 16 | var retryableTask = async.retryable(3, function(arg, callback) { 17 | callCount++; 18 | assert.strictEqual(arg, 42); 19 | callback('fail', callCount); 20 | }); 21 | retryableTask(42, function(err, res) { 22 | assert.ok(err); 23 | assert.strictEqual(res, 3); 24 | done(); 25 | }); 26 | }); 27 | 28 | it('should work as an embedded task', function(done) { 29 | 30 | var retryResult = 'RETRY'; 31 | var fooResults; 32 | var retryResults; 33 | async.auto({ 34 | dep: async.constant('dep'), 35 | foo: ['dep', function(res, callback) { 36 | fooResults = res; 37 | callback(null, 'FOO'); 38 | }], 39 | retry: ['dep', async.retryable(function(res, callback) { 40 | retryResults = res; 41 | callback(null, retryResult); 42 | })] 43 | }, function(err, res) { 44 | if (err) { 45 | return done(err); 46 | } 47 | assert.strictEqual(res.retry, retryResult); 48 | assert.strictEqual(fooResults, retryResults); 49 | done(); 50 | }); 51 | }); 52 | 53 | it('should execute even if callback function length is more than 2', function(done) { 54 | 55 | async.autoInject({ 56 | a: [async.retryable(function(callback) { 57 | callback(null, 'a'); 58 | })], 59 | b: ['a', async.retryable(function(a, callback) { 60 | callback(null, 'b'); 61 | })], 62 | c: ['a', 'b', async.retryable(function(a, b, callback) { 63 | callback(null, 'c'); 64 | })], 65 | d: ['a', 'b', 'c', async.retryable(function(a, b, c, callback) { 66 | callback(null, 'd'); 67 | })], 68 | e: ['a', 'b', 'c', 'd', async.retryable(function(a, b, c, d, callback) { 69 | callback(null, 'e'); 70 | })], 71 | f: ['a', 'b', 'c', 'd', 'e', async.retryable(function(a, b, c, d, e, callback) { 72 | callback(null, 'f'); 73 | })] 74 | }, function(err, res) { 75 | if (err) { 76 | return done(err); 77 | } 78 | assert.deepStrictEqual(res, { 79 | a: 'a', 80 | b: 'b', 81 | c: 'c', 82 | d: 'd', 83 | e: 'e', 84 | f: 'f' 85 | }); 86 | done(); 87 | }); 88 | }); 89 | 90 | it('should work as sn embedded task with interval', function(done) { 91 | 92 | var start = Date.now(); 93 | var opts = { 94 | times: 3, 95 | interval: delay * 3 96 | }; 97 | async.auto({ 98 | foo: function(callback) { 99 | callback(null, 'FOO'); 100 | }, 101 | retry: async.retryable(opts, function(callback) { 102 | callback('err'); 103 | }) 104 | }, function(err) { 105 | assert.ok(err); 106 | var diff = Date.now() - start; 107 | assert(diff > delay * (opts.times - 1)); 108 | done(); 109 | }); 110 | }); 111 | 112 | }); 113 | -------------------------------------------------------------------------------- /test/controlFlow/test.seq.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | var delay = require('../config').delay; 10 | 11 | parallel('#seq', function() { 12 | 13 | it('should execute in order of insertion', function(done) { 14 | 15 | var add2 = function(n, cb) { 16 | assert.strictEqual(n, 3); 17 | setTimeout(function() { 18 | cb(null, n + 2); 19 | }, 50); 20 | }; 21 | var mul3 = function(n, cb) { 22 | assert.strictEqual(n, 5); 23 | setTimeout(function() { 24 | cb(null, n * 3); 25 | }, 15); 26 | }; 27 | var add1 = function(n, cb) { 28 | assert.strictEqual(n, 15); 29 | setTimeout(function() { 30 | cb(null, n + 1); 31 | }, 100); 32 | }; 33 | var add2mul3add1 = async.seq(add2, mul3, add1); 34 | 35 | add2mul3add1(3, function(err, res) { 36 | if (err) { 37 | return done(err); 38 | } 39 | assert.strictEqual(res, 16); 40 | done(); 41 | }); 42 | }); 43 | 44 | it('should execute in order of insertion with binding', function(done) { 45 | 46 | var pow2 = function(n, cb) { 47 | var self = this; 48 | assert.strictEqual(n, 3); 49 | setTimeout(function() { 50 | cb(null, self.pow(n, 2)); 51 | }, 50); 52 | }; 53 | var mul3 = function(n, cb) { 54 | assert.strictEqual(n, 9); 55 | setTimeout(function() { 56 | cb(null, n * 3); 57 | }, 15); 58 | }; 59 | var pow3 = function(n, cb) { 60 | var self = this; 61 | assert.strictEqual(n, 27); 62 | setTimeout(function() { 63 | cb(null, self.pow(n, 3)); 64 | }, 100); 65 | }; 66 | 67 | var add2mul3add1 = async.seq(pow2, mul3, pow3); 68 | 69 | add2mul3add1.call(Math, 3, function(err, res) { 70 | if (err) { 71 | return done(err); 72 | } 73 | assert.strictEqual(res, 19683); 74 | done(); 75 | }); 76 | }); 77 | 78 | it('should execute without callback', function(done) { 79 | 80 | var testcontext = { 81 | name: 'foo' 82 | }; 83 | var add2 = function (n, cb) { 84 | assert.strictEqual(this, testcontext); 85 | setTimeout(function () { 86 | cb(null, n + 2); 87 | }, delay * 2); 88 | }; 89 | var mul3 = function () { 90 | assert.strictEqual(this, testcontext); 91 | setTimeout(done, delay); 92 | }; 93 | var add2mul3 = async.seq(add2, mul3); 94 | add2mul3.call(testcontext, 3); 95 | }); 96 | 97 | it('should throw error', function(done) { 98 | 99 | var add2 = function(n, cb) { 100 | assert.strictEqual(n, 3); 101 | setTimeout(function() { 102 | cb(null, n + 2); 103 | }, 50); 104 | }; 105 | var mul3 = function(n, cb) { 106 | assert.strictEqual(n, 5); 107 | setTimeout(function() { 108 | cb(new Error('error')); 109 | }, 15); 110 | }; 111 | var add1 = function(n, cb) { 112 | setTimeout(function() { 113 | cb(null, n + 1); 114 | }, 100); 115 | }; 116 | var add2mul3add1 = async.seq(add2, mul3, add1); 117 | 118 | add2mul3add1(3, function(err) { 119 | assert.ok(err); 120 | done(); 121 | }); 122 | }); 123 | 124 | }); 125 | -------------------------------------------------------------------------------- /test/controlFlow/test.series.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var _ = require('lodash'); 8 | var parallel = require('mocha.parallel'); 9 | 10 | var async = global.async || require('../../'); 11 | var delay = require('../config').delay; 12 | var util = require('../util'); 13 | 14 | function createTasks(order, numbers) { 15 | 16 | return _.transform(numbers, function(memo, num, index) { 17 | memo[index] = function(callback) { 18 | var self = this; 19 | setTimeout(function() { 20 | order.push(num); 21 | if (self && self.round) { 22 | num = self.round(num); 23 | } 24 | callback(null, num * 2); 25 | }, num * delay); 26 | }; 27 | }); 28 | } 29 | 30 | parallel('#series', function() { 31 | 32 | it('should execute to series by tasks of array', function(done) { 33 | 34 | var order = []; 35 | var numbers = [1, 3, 2, 4]; 36 | var tasks = createTasks(order, numbers); 37 | tasks.push(function(cb) { 38 | setTimeout(function() { 39 | order.push(5); 40 | cb(null, 5, 5); 41 | }, delay * 5); 42 | }); 43 | 44 | async.series(tasks, function(err, res) { 45 | if (err) { 46 | return done(err); 47 | } 48 | assert.deepStrictEqual(res, [2, 6, 4, 8, [5, 5]]); 49 | assert.deepStrictEqual(order, [1, 3, 2, 4, 5]); 50 | done(); 51 | }); 52 | }); 53 | 54 | it('should execute to series by tasks of object', function(done) { 55 | 56 | var order = []; 57 | var numbers = { 58 | a: 4, 59 | b: 2, 60 | c: 1, 61 | d: 3 62 | }; 63 | var tasks = createTasks(order, numbers); 64 | 65 | async.series(tasks, function(err, res) { 66 | if (err) { 67 | return done(err); 68 | } 69 | assert.deepStrictEqual(res, { 70 | a: 8, 71 | b: 4, 72 | c: 2, 73 | d: 6 74 | }); 75 | assert.deepStrictEqual(order, [4, 2, 1, 3]); 76 | done(); 77 | }); 78 | }); 79 | 80 | it('should execute to series by tasks of array without binding', function(done) { 81 | 82 | var order = []; 83 | var numbers = [1.2, 2.4, 1.5, 3.6]; 84 | var tasks = createTasks(order, numbers); 85 | 86 | async.series(tasks, function(err, res) { 87 | if (err) { 88 | return done(err); 89 | } 90 | assert.deepStrictEqual(res, [2.4, 4.8, 3, 7.2]); 91 | assert.deepStrictEqual(order, [1.2, 2.4, 1.5, 3.6]); 92 | done(); 93 | }, Math); 94 | }); 95 | 96 | it('should execute to series by tasks of object without binding', function(done) { 97 | 98 | var order = []; 99 | var numbers = { 100 | a: 1.2, 101 | b: 2.4, 102 | c: 1.5, 103 | d: 3.6 104 | }; 105 | var tasks = createTasks(order, numbers); 106 | 107 | async.series(tasks, function(err, res) { 108 | if (err) { 109 | return done(err); 110 | } 111 | assert.deepStrictEqual(res, { 112 | a: 2.4, 113 | b: 4.8, 114 | c: 3, 115 | d: 7.2 116 | }); 117 | assert.deepStrictEqual(order, [1.2, 2.4, 1.5, 3.6]); 118 | done(); 119 | }, Math); 120 | }); 121 | 122 | it('should execute on asynchronous', function(done) { 123 | 124 | var sync = true; 125 | var numbers = [1, 3, 2, 4]; 126 | var tasks = _.map(numbers, function(n) { 127 | return function(next) { 128 | next(null, n); 129 | }; 130 | }); 131 | async.series(tasks, function(err, res) { 132 | if (err) { 133 | return done(err); 134 | } 135 | assert.strictEqual(sync, false); 136 | assert.deepStrictEqual(res, [1, 3, 2, 4]); 137 | done(); 138 | }); 139 | sync = false; 140 | }); 141 | 142 | it('should return response immediately if array task is empty', function(done) { 143 | 144 | var tasks = []; 145 | async.series(tasks, function(err, res) { 146 | if (err) { 147 | return done(err); 148 | } 149 | assert.deepStrictEqual(res, []); 150 | done(); 151 | }); 152 | }); 153 | 154 | it('should return response immediately if object task is empty', function(done) { 155 | 156 | var tasks = {}; 157 | async.series(tasks, function(err, res) { 158 | if (err) { 159 | return done(err); 160 | } 161 | assert.deepStrictEqual(res, {}); 162 | done(); 163 | }); 164 | }); 165 | 166 | it('should return response immediately if task is not collection', function(done) { 167 | 168 | async.series('test', function(err, res) { 169 | if (err) { 170 | return done(err); 171 | } 172 | assert.strictEqual(res, undefined); 173 | done(); 174 | }); 175 | }); 176 | 177 | it('should throw error', function(done) { 178 | 179 | var order = []; 180 | var numbers = [1, 3, 2, 4]; 181 | var tasks = createTasks(order, numbers); 182 | var errorTask = function(next) { 183 | next('error'); 184 | }; 185 | tasks.splice(2, 0, errorTask); 186 | 187 | async.series(tasks, function(err) { 188 | assert.ok(err); 189 | done(); 190 | }); 191 | }); 192 | 193 | it('should throw error if double callback', function(done) { 194 | 195 | var errorCallCount = 0; 196 | setTimeout(function() { 197 | assert.strictEqual(errorCallCount, 1); 198 | done(); 199 | }, delay); 200 | 201 | domain.create() 202 | .on('error', util.errorChecker) 203 | .on('error', function() { 204 | errorCallCount++; 205 | }) 206 | .run(function() { 207 | var tasks = [function(next) { 208 | process.nextTick(next); 209 | process.nextTick(next); 210 | }]; 211 | async.series(tasks); 212 | }); 213 | }); 214 | 215 | it('should avoid double callback', function(done) { 216 | 217 | var called = false; 218 | var tasks = _.times(3, function(n) { 219 | return function(callback) { 220 | try { 221 | callback('error' + n); 222 | } catch (exception) { 223 | try { 224 | callback(exception); 225 | } catch(e) { 226 | assert.ok(e); 227 | util.errorChecker(e); 228 | } 229 | done(); 230 | } 231 | }; 232 | }); 233 | async.series(tasks, function(err) { 234 | assert.ok(err); 235 | assert.strictEqual(called, false); 236 | called = true; 237 | async.nothing(); 238 | }); 239 | }); 240 | 241 | }); 242 | -------------------------------------------------------------------------------- /test/controlFlow/test.timeout.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | var delay = require('../config').delay; 10 | 11 | parallel('#timeout', function() { 12 | 13 | it('timeout with series', function(done) { 14 | async.series([ 15 | async.timeout(function(callback) { 16 | setTimeout(function() { 17 | callback(null, 'I did not time out'); 18 | }, delay); 19 | }, delay * 2), 20 | async.timeout(function(callback) { 21 | setTimeout(function() { 22 | callback(null, 'I will time out'); 23 | }, delay * 3); 24 | }, delay * 2) 25 | ], function(err, res) { 26 | assert.ok(err); 27 | assert.strictEqual(err.code, 'ETIMEDOUT'); 28 | assert.strictEqual(err.message, 'Callback function "anonymous" timed out.'); 29 | assert.strictEqual(res[0], 'I did not time out'); 30 | done(); 31 | }); 32 | }); 33 | 34 | it('timeout with parallel', function(done) { 35 | 36 | var info = { info: 'info' }; 37 | async.parallel([ 38 | async.timeout(function(callback) { 39 | setTimeout(function() { 40 | callback(null, 'I did not time out'); 41 | }, delay); 42 | }, delay * 2), 43 | async.timeout(function timer(callback) { 44 | setTimeout(function() { 45 | callback(null, 'I will time out'); 46 | }, delay * 3); 47 | }, delay * 2, info) 48 | ], function(err, res) { 49 | assert.ok(err); 50 | assert.strictEqual(err.code, 'ETIMEDOUT'); 51 | assert.strictEqual(err.message, 'Callback function "timer" timed out.'); 52 | assert.strictEqual(err.info, info); 53 | assert.strictEqual(res[0], 'I did not time out'); 54 | done(); 55 | }); 56 | }); 57 | 58 | it('should throw error', function(done) { 59 | 60 | async.parallel([ 61 | async.timeout(function(callback) { 62 | setTimeout(function() { 63 | callback(); 64 | }, delay); 65 | }, delay * 2), 66 | async.timeout(function(callback) { 67 | setTimeout(function() { 68 | callback(null, 2, 2, 2); 69 | }, delay); 70 | }, delay * 2), 71 | async.timeout(function(callback) { 72 | setTimeout(function() { 73 | callback(new Error('error')); 74 | }, delay * 2); 75 | }, delay * 4) 76 | ], function(err) { 77 | assert.ok(err); 78 | assert.strictEqual(err.message, 'error'); 79 | done(); 80 | }); 81 | }); 82 | 83 | }); 84 | -------------------------------------------------------------------------------- /test/controlFlow/test.times.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | var delay = require('../config').delay; 11 | var util = require('../util'); 12 | 13 | function timeItrator(order) { 14 | 15 | return function(num, callback) { 16 | 17 | var self = this; 18 | 19 | setTimeout(function() { 20 | 21 | order.push(num); 22 | if (self && self.pow) { 23 | num = self.pow(num, 2); 24 | } 25 | 26 | callback(null, num); 27 | }, num % 2 === 0 ? delay : 3 * delay); 28 | }; 29 | } 30 | 31 | parallel('#times', function() { 32 | 33 | it('should execute iterator', function(done) { 34 | 35 | var n = 3; 36 | var order = []; 37 | async.times(n, timeItrator(order), function(err, res) { 38 | if (err) { 39 | return done(err); 40 | } 41 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 42 | assert.deepStrictEqual(res, [0, 1, 2]); 43 | assert.deepStrictEqual(order, [0, 2, 1]); 44 | done(); 45 | }); 46 | }); 47 | 48 | it('should execute iterator even if num is string', function(done) { 49 | 50 | var n = '3'; 51 | var order = []; 52 | async.times(n, timeItrator(order), function(err, res) { 53 | if (err) { 54 | return done(err); 55 | } 56 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 57 | assert.deepStrictEqual(res, [0, 1, 2]); 58 | assert.deepStrictEqual(order, [0, 2, 1]); 59 | done(); 60 | }); 61 | }); 62 | 63 | it('should execute iterator without binding', function(done) { 64 | 65 | var n = 3; 66 | var order = []; 67 | async.times(n, timeItrator(order), function(err, res) { 68 | if (err) { 69 | return done(err); 70 | } 71 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 72 | assert.deepStrictEqual(res, [0, 1, 2]); 73 | assert.deepStrictEqual(order, [0, 2, 1]); 74 | done(); 75 | }, Math); 76 | }); 77 | 78 | it('should return response immediately', function(done) { 79 | 80 | var n = 0; 81 | var order = []; 82 | async.times(n, timeItrator(order), function(err, res) { 83 | if (err) { 84 | return done(err); 85 | } 86 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 87 | assert.deepStrictEqual(res, []); 88 | assert.deepStrictEqual(order, []); 89 | done(); 90 | }); 91 | }); 92 | 93 | it('should throw error', function(done) { 94 | 95 | var n = 4; 96 | var iterator = function(n, next) { 97 | next(n === 2); 98 | }; 99 | async.times(n, iterator, function(err) { 100 | assert.ok(err); 101 | setTimeout(done, delay); 102 | }); 103 | }); 104 | 105 | it('should throw error if double callback', function(done) { 106 | 107 | var errorCallCount = 0; 108 | setTimeout(function() { 109 | assert.strictEqual(errorCallCount, 4); 110 | done(); 111 | }, delay); 112 | 113 | domain.create() 114 | .on('error', util.errorChecker) 115 | .on('error', function() { 116 | errorCallCount++; 117 | }) 118 | .run(function() { 119 | var iterator = function(num, callback) { 120 | process.nextTick(callback); 121 | process.nextTick(callback); 122 | }; 123 | async.times(4, iterator); 124 | }); 125 | }); 126 | 127 | }); 128 | 129 | parallel('#timesSeries', function() { 130 | 131 | it('should execute iterator', function(done) { 132 | 133 | var n = 3; 134 | var order = []; 135 | async.timesSeries(n, timeItrator(order), function(err, res) { 136 | if (err) { 137 | return done(err); 138 | } 139 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 140 | assert.deepStrictEqual(res, [0, 1, 2]); 141 | assert.deepStrictEqual(order, [0, 1, 2]); 142 | done(); 143 | }); 144 | }); 145 | 146 | it('should execute iterator even if num is string', function(done) { 147 | 148 | var n = '3'; 149 | var order = []; 150 | async.timesSeries(n, timeItrator(order), function(err, res) { 151 | if (err) { 152 | return done(err); 153 | } 154 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 155 | assert.deepStrictEqual(res, [0, 1, 2]); 156 | assert.deepStrictEqual(order, [0, 1, 2]); 157 | done(); 158 | }); 159 | }); 160 | 161 | it('should execute iterator without binding', function(done) { 162 | 163 | var n = 3; 164 | var order = []; 165 | async.timesSeries(n, timeItrator(order), function(err, res) { 166 | if (err) { 167 | return done(err); 168 | } 169 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 170 | assert.deepStrictEqual(res, [0, 1, 2]); 171 | assert.deepStrictEqual(order, [0, 1, 2]); 172 | done(); 173 | }, Math); 174 | }); 175 | 176 | it('should execute on asynchronous', function(done) { 177 | 178 | var sync = true; 179 | var n = 3; 180 | var iterator = function(n, callback) { 181 | callback(null, n); 182 | }; 183 | async.timesSeries(n, iterator, function(err, result) { 184 | if (err) { 185 | return done(err); 186 | } 187 | assert.strictEqual(sync, false); 188 | assert.deepStrictEqual(result, [0, 1, 2]); 189 | done(); 190 | }); 191 | sync = false; 192 | }); 193 | 194 | it('should return response immediately', function(done) { 195 | 196 | var n = 0; 197 | var order = []; 198 | async.timesSeries(n, timeItrator(order), function(err, res) { 199 | if (err) { 200 | return done(err); 201 | } 202 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 203 | assert.deepStrictEqual(res, []); 204 | assert.deepStrictEqual(order, []); 205 | done(); 206 | }); 207 | }); 208 | 209 | it('should throw error', function(done) { 210 | 211 | var n = 4; 212 | var iterator = function(n, next) { 213 | next(n === 2); 214 | }; 215 | async.timesSeries(n, iterator, function(err) { 216 | assert.ok(err); 217 | done(); 218 | }); 219 | }); 220 | 221 | it('should throw error if double callback', function(done) { 222 | 223 | var errorCallCount = 0; 224 | setTimeout(function() { 225 | assert.strictEqual(errorCallCount, 4); 226 | done(); 227 | }, delay); 228 | 229 | domain.create() 230 | .on('error', util.errorChecker) 231 | .on('error', function() { 232 | errorCallCount++; 233 | }) 234 | .run(function() { 235 | var iterator = function(num, callback) { 236 | process.nextTick(callback); 237 | process.nextTick(callback); 238 | }; 239 | async.timesSeries(4, iterator); 240 | }); 241 | }); 242 | 243 | }); 244 | 245 | parallel('#timesLimit', function() { 246 | 247 | it('should execute iterator', function(done) { 248 | 249 | var n = 5; 250 | var order = []; 251 | async.timesLimit(n, 2, timeItrator(order), function(err, res) { 252 | if (err) { 253 | return done(err); 254 | } 255 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 256 | assert.deepStrictEqual(res, [0, 1, 2, 3, 4]); 257 | assert.deepStrictEqual(order, [0, 2, 1, 4, 3]); 258 | done(); 259 | }); 260 | }); 261 | 262 | it('should execute iterator even if num is string', function(done) { 263 | 264 | var n = '5'; 265 | var order = []; 266 | async.timesLimit(n, 2, timeItrator(order), function(err, res) { 267 | if (err) { 268 | return done(err); 269 | } 270 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 271 | assert.deepStrictEqual(res, [0, 1, 2, 3, 4]); 272 | assert.deepStrictEqual(order, [0, 2, 1, 4, 3]); 273 | done(); 274 | }); 275 | }); 276 | 277 | it('should execute iterator without binding', function(done) { 278 | 279 | var n = 7; 280 | var order = []; 281 | async.timesLimit(n, 2, timeItrator(order), function(err, res) { 282 | if (err) { 283 | return done(err); 284 | } 285 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 286 | assert.deepStrictEqual(res, [0, 1, 2, 3, 4, 5, 6]); 287 | assert.deepStrictEqual(order, [0, 2, 1, 4, 3, 6, 5]); 288 | done(); 289 | }, Math); 290 | }); 291 | 292 | it('should execute like parallel if limit is Infinity', function(done) { 293 | 294 | var n = 5; 295 | var order = []; 296 | var iterator = function(n, done) { 297 | setTimeout(function() { 298 | order.push(n); 299 | done(null, n); 300 | }, n * 30); 301 | }; 302 | async.timesLimit(n, Infinity, iterator, function(err, res) { 303 | if (err) { 304 | return done(err); 305 | } 306 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 307 | assert.deepStrictEqual(res, [0, 1, 2, 3, 4]); 308 | assert.deepStrictEqual(order, [0, 1, 2, 3, 4]); 309 | done(); 310 | }); 311 | }); 312 | 313 | it('should return response immediately', function(done) { 314 | 315 | var n = 0; 316 | var order = []; 317 | async.timesLimit(n, 2, timeItrator(order), function(err, res) { 318 | if (err) { 319 | return done(err); 320 | } 321 | assert.strictEqual(Object.prototype.toString.call(res), '[object Array]'); 322 | assert.deepStrictEqual(res, []); 323 | assert.deepStrictEqual(order, []); 324 | done(); 325 | }); 326 | }); 327 | 328 | it('should execute on asynchronous', function(done) { 329 | 330 | var sync = true; 331 | var n = 5; 332 | var iterator = function(n, callback) { 333 | callback(null, n); 334 | }; 335 | async.timesLimit(n, 2, iterator, function(err, result) { 336 | if (err) { 337 | return done(err); 338 | } 339 | assert.strictEqual(sync, false); 340 | assert.deepStrictEqual(result, [0, 1, 2, 3, 4]); 341 | done(); 342 | }); 343 | sync = false; 344 | }); 345 | 346 | it('should throw error', function(done) { 347 | 348 | var n = 6; 349 | var iterator = function(n, next) { 350 | next(n === 4); 351 | }; 352 | async.timesLimit(n, 3, iterator, function(err) { 353 | assert.ok(err); 354 | setTimeout(done, delay); 355 | }); 356 | }); 357 | 358 | it('should throw error if double callback', function(done) { 359 | 360 | var errorCallCount = 0; 361 | setTimeout(function() { 362 | assert.strictEqual(errorCallCount, 4); 363 | done(); 364 | }, delay); 365 | 366 | domain.create() 367 | .on('error', util.errorChecker) 368 | .on('error', function() { 369 | errorCallCount++; 370 | }) 371 | .run(function() { 372 | var iterator = function(num, callback) { 373 | process.nextTick(callback); 374 | process.nextTick(callback); 375 | }; 376 | async.timesLimit(4, 2, iterator); 377 | }); 378 | }); 379 | 380 | }); 381 | -------------------------------------------------------------------------------- /test/controlFlow/test.tryEach.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = global.async || require('../../'); 9 | 10 | parallel('#tryEach', function() { 11 | 12 | it('should execute', function(done) { 13 | 14 | var result = 'test'; 15 | async.tryEach([ 16 | function(callback) { 17 | callback(null, result); 18 | } 19 | ], function(err, res) { 20 | if (err) { 21 | return done(err); 22 | } 23 | assert.strictEqual(res, result); 24 | done(); 25 | }); 26 | }); 27 | 28 | it('should execute with object', function(done) { 29 | 30 | var result = 'test'; 31 | async.tryEach({ 32 | task1: function(callback) { 33 | callback(null, result); 34 | }, 35 | task2: function() { 36 | assert(false); 37 | } 38 | }, function(err, res) { 39 | if (err) { 40 | return done(err); 41 | } 42 | assert.strictEqual(res, result); 43 | done(); 44 | }); 45 | }); 46 | 47 | it('should return multiple arguments', function(done) { 48 | 49 | var results = ['arg1', 'arg2']; 50 | async.tryEach([ 51 | function(callback) { 52 | callback(null, results[0], results[1]); 53 | } 54 | ], function(err, res) { 55 | if (err) { 56 | return done(err); 57 | } 58 | assert.deepStrictEqual(res, results); 59 | done(); 60 | }); 61 | }); 62 | 63 | it('should execute second task if first task is failed', function(done) { 64 | 65 | async.tryEach([ 66 | function(callback) { 67 | callback(new Error('failed'), 'task1'); 68 | }, 69 | function(callback) { 70 | callback(null, 'task2'); 71 | } 72 | ], function(err, res) { 73 | if (err) { 74 | return done(err); 75 | } 76 | assert.strictEqual(res, 'task2'); 77 | done(); 78 | }); 79 | 80 | }); 81 | 82 | it('should return an error if all tasks are failed', function(done) { 83 | 84 | async.tryEach([ 85 | function(callback) { 86 | callback(new Error('failed1'), 'task1'); 87 | }, 88 | function(callback) { 89 | callback(new Error('failed2'), 'task2'); 90 | } 91 | ], function(err) { 92 | assert.ok(err); 93 | assert.strictEqual(err.message, 'failed2'); 94 | done(); 95 | }); 96 | }); 97 | 98 | it('should not cause any error if task is empty', function(done) { 99 | 100 | async.tryEach([], function(err, res) { 101 | if (err) { 102 | return done(err); 103 | } 104 | assert.strictEqual(res, undefined); 105 | done(); 106 | }); 107 | }); 108 | 109 | it('should not cause any error if task is string', function(done) { 110 | 111 | async.tryEach('test', function(err, res) { 112 | if (err) { 113 | return done(err); 114 | } 115 | assert.strictEqual(res, undefined); 116 | done(); 117 | }); 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /test/controlFlow/test.until.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | 11 | parallel('#until', function() { 12 | 13 | it('should execute until test is true', function(done) { 14 | 15 | var count = 0; 16 | var limit = 5; 17 | var order = { 18 | test: [], 19 | iterator: [] 20 | }; 21 | var test = function() { 22 | order.test.push(count); 23 | return count === limit; 24 | }; 25 | var iterator = function(callback) { 26 | order.iterator.push(count++); 27 | callback(null, count); 28 | }; 29 | 30 | async.until(test, iterator, function(err, res) { 31 | if (err) { 32 | return done(err); 33 | } 34 | 35 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 36 | assert.deepStrictEqual(order.test, [0, 1, 2, 3, 4, 5]); 37 | assert.strictEqual(res, 5); 38 | done(); 39 | }); 40 | }); 41 | 42 | it('should execute without binding until test is false', function(done) { 43 | 44 | var count = 0; 45 | var limit = 5; 46 | var order = { 47 | test: [], 48 | iterator: [] 49 | }; 50 | var result = []; 51 | var test = function() { 52 | order.test.push(count); 53 | return count === limit; 54 | }; 55 | var iterator = function(callback) { 56 | assert.strictEqual(this, undefined); 57 | result.push(count * count); 58 | order.iterator.push(count++); 59 | callback(null, count); 60 | }; 61 | 62 | async.until(test, iterator, function(err, res) { 63 | if (err) { 64 | return done(err); 65 | } 66 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 67 | assert.deepStrictEqual(order.test, [0, 1, 2, 3, 4, 5]); 68 | assert.deepStrictEqual(result, [0, 1, 4, 9, 16]); 69 | assert.strictEqual(res, 5); 70 | done(); 71 | }, Math); 72 | }); 73 | 74 | it('should execute on asynchronous', function(done) { 75 | 76 | var sync = true; 77 | var count = 0; 78 | var limit = 5; 79 | var test = function() { 80 | return count === limit; 81 | }; 82 | var iterator = function(callback) { 83 | count++; 84 | callback(); 85 | }; 86 | async.until(test, iterator, function(err) { 87 | if (err) { 88 | return done(err); 89 | } 90 | assert.strictEqual(sync, false); 91 | done(); 92 | }); 93 | sync = false; 94 | }); 95 | 96 | it('should execute callback immediately if first test is truthy', function(done) { 97 | 98 | var test = function() { 99 | return true; 100 | }; 101 | var iterator = function(callback) { 102 | callback(); 103 | }; 104 | async.until(test, iterator, done); 105 | }); 106 | 107 | it('should get multiple result', function(done) { 108 | 109 | var count = 0; 110 | var limit = 5; 111 | var test = function() { 112 | assert.strictEqual(arguments.length, count); 113 | return count === limit; 114 | }; 115 | var iterator = function(callback) { 116 | callback.apply(null, [null].concat(_.range(++count))); 117 | }; 118 | async.until(test, iterator, function(err, res1, res2, res3, res4) { 119 | if (err) { 120 | return done(err); 121 | } 122 | assert.strictEqual(count, 5); 123 | assert.strictEqual(arguments.length, 6); 124 | assert.strictEqual(res1, 0); 125 | assert.strictEqual(res2, 1); 126 | assert.strictEqual(res3, 2); 127 | assert.strictEqual(res4, 3); 128 | done(); 129 | }); 130 | }); 131 | 132 | it('should throw error', function(done) { 133 | 134 | var count = 0; 135 | var limit = 5; 136 | var order = { 137 | test: [], 138 | iterator: [] 139 | }; 140 | var test = function() { 141 | order.test.push(count); 142 | return count === limit; 143 | }; 144 | var iterator = function(callback) { 145 | order.iterator.push(count++); 146 | callback(count === 3); 147 | }; 148 | async.until(test, iterator, function(err) { 149 | assert.ok(err); 150 | assert.deepStrictEqual(order.iterator, [0, 1, 2]); 151 | assert.deepStrictEqual(order.test, [0, 1, 2]); 152 | done(); 153 | }); 154 | }); 155 | 156 | }); 157 | 158 | parallel('#doUntil', function() { 159 | 160 | it('should execute until test is false', function(done) { 161 | 162 | var count = 0; 163 | var limit = 5; 164 | var order = { 165 | test: [], 166 | iterator: [] 167 | }; 168 | var test = function() { 169 | order.test.push(count); 170 | return count === limit; 171 | }; 172 | var iterator = function(callback) { 173 | order.iterator.push(count++); 174 | callback(null, count); 175 | }; 176 | 177 | async.doUntil(iterator, test, function(err, res) { 178 | if (err) { 179 | return done(err); 180 | } 181 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 182 | assert.deepStrictEqual(order.test, [1, 2, 3, 4, 5]); 183 | assert.strictEqual(res, 5); 184 | done(); 185 | }); 186 | }); 187 | 188 | it('should execute without binding until test is false', function(done) { 189 | 190 | var count = 0; 191 | var limit = 5; 192 | var order = { 193 | test: [], 194 | iterator: [] 195 | }; 196 | var result = []; 197 | var test = function() { 198 | order.test.push(count); 199 | return count === limit; 200 | }; 201 | var iterator = function(callback) { 202 | assert.strictEqual(this, undefined); 203 | result.push(count * count); 204 | order.iterator.push(count++); 205 | callback(null, count); 206 | }; 207 | 208 | async.doUntil(iterator, test, function(err, res) { 209 | if (err) { 210 | return done(err); 211 | } 212 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 213 | assert.deepStrictEqual(order.test, [1, 2, 3, 4, 5]); 214 | assert.deepStrictEqual(result, [0, 1, 4, 9, 16]); 215 | assert.strictEqual(res, 5); 216 | done(); 217 | }, Math); 218 | }); 219 | 220 | it('should execute until test is false and apply params', function(done) { 221 | 222 | var count = 0; 223 | var limit = 5; 224 | var order = { 225 | test: [], 226 | iterator: [] 227 | }; 228 | var test = function(c) { 229 | order.test.push(c); 230 | return c < limit; 231 | }; 232 | var iterator = function(callback) { 233 | order.iterator.push(count++); 234 | callback(null, count); 235 | }; 236 | 237 | async.doWhilst(iterator, test, function(err) { 238 | if (err) { 239 | return done(err); 240 | } 241 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 242 | assert.deepStrictEqual(order.test, [1, 2, 3, 4, 5]); 243 | done(); 244 | }); 245 | 246 | }); 247 | 248 | it('should execute on asynchronous', function(done) { 249 | 250 | var sync = true; 251 | var count = 0; 252 | var limit = 5; 253 | var test = function() { 254 | return count === limit; 255 | }; 256 | var iterator = function(callback) { 257 | count++; 258 | callback(); 259 | }; 260 | async.doUntil(iterator, test, function(err) { 261 | if (err) { 262 | return done(err); 263 | } 264 | assert.strictEqual(sync, false); 265 | done(); 266 | }); 267 | sync = false; 268 | }); 269 | 270 | it('should get multiple result', function(done) { 271 | 272 | var count = 0; 273 | var limit = 5; 274 | var test = function(arg) { 275 | assert.strictEqual(arg, 0); 276 | assert.strictEqual(arguments.length, count); 277 | return count === limit; 278 | }; 279 | var iterator = function(callback) { 280 | callback.apply(null, [null].concat(_.range(++count))); 281 | }; 282 | async.doUntil(iterator, test, function(err, res1, res2, res3, res4) { 283 | if (err) { 284 | return done(err); 285 | } 286 | assert.strictEqual(count, 5); 287 | assert.strictEqual(arguments.length, 6); 288 | assert.strictEqual(res1, 0); 289 | assert.strictEqual(res2, 1); 290 | assert.strictEqual(res3, 2); 291 | assert.strictEqual(res4, 3); 292 | done(); 293 | }); 294 | }); 295 | 296 | it('should throw error', function(done) { 297 | 298 | var count = 0; 299 | var limit = 5; 300 | var order = { 301 | test: [], 302 | iterator: [] 303 | }; 304 | var test = function() { 305 | order.test.push(count); 306 | return count === limit; 307 | }; 308 | var iterator = function(callback) { 309 | order.iterator.push(count++); 310 | callback(count === 3); 311 | }; 312 | 313 | async.doUntil(iterator, test, function(err) { 314 | assert.ok(err); 315 | assert.deepStrictEqual(order.iterator, [0, 1, 2]); 316 | assert.deepStrictEqual(order.test, [1, 2]); 317 | done(); 318 | }); 319 | }); 320 | 321 | }); 322 | -------------------------------------------------------------------------------- /test/controlFlow/test.waterfall.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | var domain = require('domain'); 6 | 7 | var _ = require('lodash'); 8 | var parallel = require('mocha.parallel'); 9 | 10 | var async = global.async || require('../../'); 11 | var delay = require('../config').delay; 12 | var util = require('../util'); 13 | 14 | function createTasks(type, numbers) { 15 | 16 | switch (type) { 17 | case 'simple': 18 | return createSimpleTasks(); 19 | case 'complex': 20 | return createComplexTasks(); 21 | } 22 | 23 | function createSimpleTasks() { 24 | 25 | var first = true; 26 | var tasks = _.transform(numbers, function(memo, num, key) { 27 | if (first) { 28 | first = false; 29 | memo[key] = function(done) { 30 | if (this === Math) { 31 | num *= 2; 32 | } 33 | done(null, num); 34 | }; 35 | } else { 36 | memo[key] = function(sum, done) { 37 | if (this === Math) { 38 | num *= 2; 39 | } 40 | done(null, sum + num); 41 | }; 42 | } 43 | }); 44 | return tasks; 45 | } 46 | 47 | function createComplexTasks() { 48 | 49 | var count = 0; 50 | var tasks = _.transform(numbers, function(memo, num, key) { 51 | if (count++ === 0) { 52 | memo[key] = function(done) { 53 | if (this === Math) { 54 | num *= 2; 55 | } 56 | done(null, num); 57 | }; 58 | } else { 59 | memo[key] = function() { 60 | if (this === Math) { 61 | num *= 2; 62 | } 63 | var args = _.toArray(arguments); 64 | var done = args.pop(); 65 | args.unshift(null); 66 | args.push(num); 67 | done.apply(null, args); 68 | }; 69 | } 70 | }); 71 | return tasks; 72 | } 73 | 74 | } 75 | 76 | parallel('#waterfall', function() { 77 | 78 | it('should execute to waterfall by collection of array', function(done) { 79 | 80 | var numbers = [1, 3, 2, 4]; 81 | var tasks = createTasks('simple', numbers); 82 | async.waterfall(tasks, function(err, res) { 83 | if (err) { 84 | return done(err); 85 | } 86 | assert.strictEqual(res, 10); 87 | done(); 88 | }); 89 | }); 90 | 91 | it('should execute simple tasks', function(done) { 92 | 93 | var numbers = [1, 3, 2, 4, 7, 8, 6, 5]; 94 | var tasks = createTasks('simple', numbers); 95 | async.waterfall(tasks, function(err, result) { 96 | if (err) { 97 | return done(err); 98 | } 99 | assert.strictEqual(result, 36); 100 | done(); 101 | }); 102 | }); 103 | 104 | it('should execute complex tasks', function(done) { 105 | 106 | var numbers = [1, 3, 2, 4, 7, 8, 6, 5]; 107 | var tasks = createTasks('complex', numbers); 108 | async.waterfall(tasks, function(err, a, b, c, d, e, f, g, h) { 109 | if (err) { 110 | return done(err); 111 | } 112 | assert.strictEqual(a, 1); 113 | assert.strictEqual(b, 3); 114 | assert.strictEqual(c, 2); 115 | assert.strictEqual(d, 4); 116 | 117 | assert.strictEqual(e, 7); 118 | assert.strictEqual(f, 8); 119 | assert.strictEqual(g, 6); 120 | assert.strictEqual(h, 5); 121 | 122 | done(); 123 | }); 124 | }); 125 | 126 | it('should throw error', function(done) { 127 | 128 | var numbers = [1, 3, 2, 4]; 129 | var tasks = createTasks('simple', numbers); 130 | var errorTask = function(res, next) { 131 | next('error'); 132 | }; 133 | tasks.splice(2, 0, errorTask); 134 | 135 | async.waterfall(tasks, function(err) { 136 | assert.ok(err); 137 | done(); 138 | }); 139 | }); 140 | 141 | it('should throw error if callback is called twice', function(done) { 142 | 143 | var errorCallCount = 0; 144 | setTimeout(function() { 145 | assert.strictEqual(errorCallCount, 1); 146 | done(); 147 | }, delay); 148 | 149 | domain.create() 150 | .on('error', util.errorChecker) 151 | .on('error', function() { 152 | errorCallCount++; 153 | }) 154 | .run(function() { 155 | var array = [ 156 | function(next) { 157 | setImmediate(function() { 158 | next(null, 'one', 'two'); 159 | }); 160 | setImmediate(function() { 161 | next(null, 'one', 'two'); 162 | }); 163 | }, 164 | 165 | function(arg1, arg2, next) { 166 | next(null, arg1, arg2, 'three'); 167 | }, 168 | 169 | function(arg1, arg2, arg3, next) { 170 | next(null, 'four'); 171 | }, 172 | 173 | function(arg1, next) { 174 | next(); 175 | } 176 | ]; 177 | async.waterfall(array); 178 | }); 179 | }); 180 | 181 | it('should throw error if task is not collection', function(done) { 182 | 183 | async.waterfall(null, function(err) { 184 | assert.strictEqual(err.message, 'First argument to waterfall must be an array of functions'); 185 | done(); 186 | }); 187 | }); 188 | 189 | it('should throw error with binding', function(done) { 190 | 191 | var numbers = [1, 3, 2, 4]; 192 | var tasks = createTasks('simple', numbers); 193 | var errorTask = function(res, next) { 194 | next('error'); 195 | }; 196 | tasks.splice(2, 0, errorTask); 197 | 198 | async.waterfall(tasks, function(err) { 199 | assert.ok(err); 200 | done(); 201 | }, Math); 202 | }); 203 | 204 | it('should avoid double callback', function(done) { 205 | 206 | var called = false; 207 | var tasks = _.times(3, function(n) { 208 | return function(callback) { 209 | try { 210 | callback('error' + n); 211 | } catch (exception) { 212 | try { 213 | callback(exception); 214 | } catch(e) { 215 | assert.ok(e); 216 | util.errorChecker(e); 217 | } 218 | done(); 219 | } 220 | }; 221 | }); 222 | async.waterfall(tasks, function(err) { 223 | assert.ok(err); 224 | assert.strictEqual(called, false); 225 | called = true; 226 | async.nothing(); 227 | }); 228 | }); 229 | 230 | it('should return response immediately if array task is empty', function(done) { 231 | 232 | var tasks = []; 233 | async.waterfall(tasks, function(err, res) { 234 | if (err) { 235 | return done(err); 236 | } 237 | assert.strictEqual(res, undefined); 238 | done(); 239 | }); 240 | }); 241 | 242 | it('multiple callback calls (trickier) @nodeonly', function(done) { 243 | 244 | var errorCallCount = 0; 245 | setTimeout(function() { 246 | assert.strictEqual(errorCallCount, 1); 247 | done(); 248 | }, delay); 249 | 250 | domain.create() 251 | .on('error', util.errorChecker) 252 | .on('error', function() { 253 | errorCallCount++; 254 | }) 255 | .run(function() { 256 | async.waterfall([ 257 | function(callback) { 258 | setTimeout(callback, 0, null, 'one', 'two'); 259 | setTimeout(callback, 10, null, 'one', 'two'); 260 | }, 261 | function(arg1, arg2, callback) { 262 | setTimeout(callback, 15, null, arg1, arg2, 'three'); 263 | } 264 | ], function () { 265 | throw new Error('should not get here'); 266 | }); 267 | }); 268 | }); 269 | 270 | }); 271 | -------------------------------------------------------------------------------- /test/controlFlow/test.whilst.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _ = require('lodash'); 7 | var parallel = require('mocha.parallel'); 8 | 9 | var async = global.async || require('../../'); 10 | var delay = require('../config').delay; 11 | 12 | parallel('#whilst', function() { 13 | 14 | it('should execute until test is false', function(done) { 15 | 16 | var count = 0; 17 | var limit = 5; 18 | var order = { 19 | test: [], 20 | iterator: [] 21 | }; 22 | var test = function() { 23 | order.test.push(count); 24 | return count < limit; 25 | }; 26 | var iterator = function(callback) { 27 | order.iterator.push(count++); 28 | callback(null, count); 29 | }; 30 | 31 | async.whilst(test, iterator, function(err, res) { 32 | if (err) { 33 | return done(err); 34 | } 35 | 36 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 37 | assert.deepStrictEqual(order.test, [0, 1, 2, 3, 4, 5]); 38 | assert.strictEqual(res, 5); 39 | done(); 40 | }); 41 | }); 42 | 43 | it('should execute without binding until test is false', function(done) { 44 | 45 | var count = 0; 46 | var limit = 5; 47 | var order = { 48 | test: [], 49 | iterator: [] 50 | }; 51 | var result = []; 52 | var test = function() { 53 | order.test.push(count); 54 | return count < limit; 55 | }; 56 | var iterator = function(callback) { 57 | assert.strictEqual(this, undefined); 58 | result.push(count * count); 59 | order.iterator.push(count++); 60 | callback(null, count); 61 | }; 62 | 63 | async.whilst(test, iterator, function(err, res) { 64 | if (err) { 65 | return done(err); 66 | } 67 | 68 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 69 | assert.deepStrictEqual(order.test, [0, 1, 2, 3, 4, 5]); 70 | assert.deepStrictEqual(result, [0, 1, 4, 9, 16]); 71 | assert.strictEqual(res, 5); 72 | done(); 73 | }, Math); 74 | }); 75 | 76 | it('should execute on asynchronous', function(done) { 77 | 78 | var sync = true; 79 | var count = 0; 80 | var limit = 5; 81 | var test = function() { 82 | return count < limit; 83 | }; 84 | var iterator = function(callback) { 85 | count++; 86 | callback(null, count); 87 | }; 88 | async.whilst(test, iterator, function(err, res) { 89 | if (err) { 90 | return done(err); 91 | } 92 | assert.strictEqual(sync, false); 93 | assert.strictEqual(res, 5); 94 | done(); 95 | }); 96 | sync = false; 97 | }); 98 | 99 | it('should execute callback immediately if first test is falsy', function(done) { 100 | 101 | var test = function() { 102 | return false; 103 | }; 104 | var iterator = function(callback) { 105 | callback(); 106 | }; 107 | async.whilst(test, iterator, done); 108 | }); 109 | 110 | it('should get multiple result', function(done) { 111 | 112 | var count = 0; 113 | var limit = 5; 114 | var test = function() { 115 | assert.strictEqual(arguments.length, count); 116 | return count < limit; 117 | }; 118 | var iterator = function(callback) { 119 | callback.apply(null, [null].concat(_.range(++count))); 120 | }; 121 | async.whilst(test, iterator, function(err, res1, res2, res3, res4) { 122 | if (err) { 123 | return done(err); 124 | } 125 | assert.strictEqual(count, 5); 126 | assert.strictEqual(arguments.length, 6); 127 | assert.strictEqual(res1, 0); 128 | assert.strictEqual(res2, 1); 129 | assert.strictEqual(res3, 2); 130 | assert.strictEqual(res4, 3); 131 | done(); 132 | }); 133 | }); 134 | 135 | it('should execute without callback', function(done) { 136 | var count = 0; 137 | var limit = 5; 138 | var test = function() { 139 | return count < limit; 140 | }; 141 | var iterator = function(callback) { 142 | count++; 143 | callback(); 144 | }; 145 | async.whilst(test, iterator); 146 | setTimeout(function() { 147 | assert.strictEqual(count, 5); 148 | done(); 149 | }, delay); 150 | }); 151 | 152 | it('should throw error', function(done) { 153 | 154 | var count = 0; 155 | var limit = 5; 156 | var order = { 157 | test: [], 158 | iterator: [] 159 | }; 160 | var result = []; 161 | var test = function() { 162 | order.test.push(count); 163 | return count < limit; 164 | }; 165 | var iterator = function(callback) { 166 | assert.strictEqual(this, undefined); 167 | result.push(count * count); 168 | order.iterator.push(count++); 169 | callback(count === 3); 170 | }; 171 | 172 | async.whilst(test, iterator, function(err) { 173 | assert.ok(err); 174 | assert.deepStrictEqual(order.iterator, [0, 1, 2]); 175 | assert.deepStrictEqual(order.test, [0, 1, 2]); 176 | assert.deepStrictEqual(result, [0, 1, 4]); 177 | done(); 178 | }, Math); 179 | }); 180 | 181 | }); 182 | 183 | parallel('#doWhilst', function() { 184 | 185 | it('should execute until test is false', function(done) { 186 | 187 | var count = 0; 188 | var limit = 5; 189 | var order = { 190 | test: [], 191 | iterator: [] 192 | }; 193 | var test = function() { 194 | order.test.push(count); 195 | return count < limit; 196 | }; 197 | var iterator = function(callback) { 198 | order.iterator.push(count++); 199 | callback(null, count); 200 | }; 201 | 202 | async.doWhilst(iterator, test, function(err, res) { 203 | if (err) { 204 | return done(err); 205 | } 206 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 207 | assert.deepStrictEqual(order.test, [1, 2, 3, 4, 5]); 208 | assert.strictEqual(res, 5); 209 | done(); 210 | }); 211 | }); 212 | 213 | it('should execute without binding until test is false', function(done) { 214 | 215 | var count = 0; 216 | var limit = 5; 217 | var order = { 218 | test: [], 219 | iterator: [] 220 | }; 221 | var result = []; 222 | var test = function() { 223 | order.test.push(count); 224 | return count < limit; 225 | }; 226 | var iterator = function(callback) { 227 | assert.strictEqual(this, undefined); 228 | result.push(count * count); 229 | order.iterator.push(count++); 230 | callback(null, count); 231 | }; 232 | 233 | async.doWhilst(iterator, test, function(err, res) { 234 | if (err) { 235 | return done(err); 236 | } 237 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 238 | assert.deepStrictEqual(order.test, [1, 2, 3, 4, 5]); 239 | assert.deepStrictEqual(result, [0, 1, 4, 9, 16]); 240 | assert.strictEqual(res, 5); 241 | done(); 242 | }, Math); 243 | }); 244 | 245 | it('should execute until test is false and apply params', function(done) { 246 | 247 | var count = 0; 248 | var limit = 5; 249 | var order = { 250 | test: [], 251 | iterator: [] 252 | }; 253 | var test = function(c) { 254 | order.test.push(c); 255 | return c < limit; 256 | }; 257 | var iterator = function(callback) { 258 | order.iterator.push(count++); 259 | callback(null, count); 260 | }; 261 | 262 | async.doWhilst(iterator, test, function(err, res) { 263 | if (err) { 264 | return done(err); 265 | } 266 | assert.deepStrictEqual(order.iterator, [0, 1, 2, 3, 4]); 267 | assert.deepStrictEqual(order.test, [1, 2, 3, 4, 5]); 268 | assert.strictEqual(res, 5); 269 | done(); 270 | }); 271 | }); 272 | 273 | it('should execute on asynchronous', function(done) { 274 | 275 | var sync = true; 276 | var count = 0; 277 | var limit = 5; 278 | var test = function() { 279 | return count < limit; 280 | }; 281 | var iterator = function(callback) { 282 | count++; 283 | callback(); 284 | }; 285 | async.doWhilst(iterator, test, function(err) { 286 | if (err) { 287 | return done(err); 288 | } 289 | assert.strictEqual(sync, false); 290 | done(); 291 | }); 292 | sync = false; 293 | }); 294 | 295 | it('should get multiple result', function(done) { 296 | 297 | var count = 0; 298 | var limit = 5; 299 | var test = function(arg) { 300 | assert.strictEqual(arg, 0); 301 | assert.strictEqual(arguments.length, count); 302 | return count < limit; 303 | }; 304 | var iterator = function(callback) { 305 | callback.apply(null, [null].concat(_.range(++count))); 306 | }; 307 | async.doWhilst(iterator, test, function(err, res1, res2, res3, res4) { 308 | if (err) { 309 | return done(err); 310 | } 311 | assert.strictEqual(count, 5); 312 | assert.strictEqual(arguments.length, 6); 313 | assert.strictEqual(res1, 0); 314 | assert.strictEqual(res2, 1); 315 | assert.strictEqual(res3, 2); 316 | assert.strictEqual(res4, 3); 317 | done(); 318 | }); 319 | }); 320 | 321 | it('should execute without callback', function(done) { 322 | var count = 0; 323 | var limit = 5; 324 | var test = function() { 325 | return count < limit; 326 | }; 327 | var iterator = function(callback) { 328 | count++; 329 | callback(); 330 | }; 331 | async.doWhilst(iterator, test); 332 | setTimeout(function() { 333 | assert.strictEqual(count, 5); 334 | done(); 335 | }, delay); 336 | }); 337 | 338 | it('should throw error', function(done) { 339 | 340 | var count = 0; 341 | var limit = 5; 342 | var order = { 343 | test: [], 344 | iterator: [] 345 | }; 346 | var result = []; 347 | var test = function() { 348 | order.test.push(count); 349 | return count < limit; 350 | }; 351 | var iterator = function(callback) { 352 | assert.strictEqual(this, undefined); 353 | result.push(count * count); 354 | order.iterator.push(count++); 355 | callback(count === 3); 356 | }; 357 | 358 | async.doWhilst(iterator, test, function(err) { 359 | assert.ok(err); 360 | assert.deepStrictEqual(order.iterator, [0, 1, 2]); 361 | assert.deepStrictEqual(order.test, [1, 2]); 362 | assert.deepStrictEqual(result, [0, 1, 4]); 363 | done(); 364 | }, Math); 365 | }); 366 | 367 | }); 368 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --ui bdd 2 | --reporter spec 3 | --timeout 5000 4 | -------------------------------------------------------------------------------- /test/other/test.alias.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#alias', function() { 11 | 12 | it('should have alias of forEach', function(done) { 13 | 14 | assert.strictEqual(async.forEach, async.each); 15 | done(); 16 | }); 17 | 18 | it('should have alias of forEachSeries', function(done) { 19 | 20 | assert.strictEqual(async.forEachSeries, async.eachSeries); 21 | done(); 22 | }); 23 | 24 | it('should have alias of forEachLimit', function(done) { 25 | 26 | assert.strictEqual(async.forEachLimit, async.eachLimit); 27 | done(); 28 | }); 29 | 30 | it('should have alias of eachOf', function(done) { 31 | 32 | assert.strictEqual(async.eachOf, async.each); 33 | done(); 34 | }); 35 | 36 | it('should have alias of eachOfSeries', function(done) { 37 | 38 | assert.strictEqual(async.eachOfSeries, async.eachSeries); 39 | done(); 40 | }); 41 | 42 | it('should have alias of eachLimit', function(done) { 43 | 44 | assert.strictEqual(async.eachOfLimit, async.eachLimit); 45 | done(); 46 | }); 47 | 48 | it('should have alias of forEachOf', function(done) { 49 | 50 | assert.strictEqual(async.forEachOf, async.each); 51 | done(); 52 | }); 53 | 54 | it('should have alias of forEachOfSeries', function(done) { 55 | 56 | assert.strictEqual(async.forEachOfSeries, async.eachSeries); 57 | done(); 58 | }); 59 | 60 | it('should have alias of forEachOfLimit', function(done) { 61 | 62 | assert.strictEqual(async.forEachOfLimit, async.eachLimit); 63 | done(); 64 | }); 65 | 66 | it('should have alias of inject', function(done) { 67 | 68 | assert.strictEqual(async.inject, async.reduce); 69 | done(); 70 | }); 71 | 72 | it('should have alias of foldl', function(done) { 73 | 74 | assert.strictEqual(async.foldl, async.reduce); 75 | done(); 76 | }); 77 | 78 | it('should have alias of foldr', function(done) { 79 | 80 | assert.strictEqual(async.foldr, async.reduceRight); 81 | done(); 82 | }); 83 | 84 | it('should have alias of any', function(done) { 85 | 86 | assert.strictEqual(async.any, async.some); 87 | done(); 88 | }); 89 | 90 | it('should have alias of all', function(done) { 91 | 92 | assert.strictEqual(async.all, async.every); 93 | done(); 94 | }); 95 | 96 | it('should have alias of angelfall', function(done) { 97 | 98 | assert.strictEqual(async.angelfall, async.angelFall); 99 | done(); 100 | }); 101 | 102 | it('should have alias of wrapSync', function(done) { 103 | 104 | assert.strictEqual(async.wrapSync, async.asyncify); 105 | done(); 106 | }); 107 | }); 108 | -------------------------------------------------------------------------------- /test/other/test.other.js: -------------------------------------------------------------------------------- 1 | /* global it, before, after */ 2 | 3 | var fs = require('fs'); 4 | var vm = require('vm'); 5 | var path = require('path'); 6 | var assert = require('assert'); 7 | 8 | var _ = require('lodash'); 9 | var parallel = require('mocha.parallel'); 10 | 11 | var async = global.async || require('../../'); 12 | var asyncPath = global.async_path || path.resolve(__dirname, '../../lib/async.js'); 13 | 14 | parallel('#nextTick', function() { 15 | 16 | 'use strict'; 17 | 18 | it('should assign setImmediate when process does not exist', function(done) { 19 | 20 | var context = { 21 | require: require, 22 | console: console, 23 | exports: exports, 24 | setTimeout: setTimeout, 25 | setImmediate: setImmediate 26 | }; 27 | vm.runInNewContext(fs.readFileSync(asyncPath), context); 28 | assert.strictEqual(typeof context.async.nextTick, 'function'); 29 | assert.notStrictEqual(context.async.nextTick, process.nextTick); 30 | assert.strictEqual(context.async.nextTick, setImmediate); 31 | context.async.nextTick(done); 32 | }); 33 | 34 | it('should assign setImmediate when process does not exist for coverage', function(done) { 35 | 36 | var _nextTick = process.nextTick; 37 | process.nextTick = undefined; 38 | delete(require.cache[asyncPath]); 39 | var async = require(asyncPath); 40 | process.nextTick = _nextTick; 41 | assert.strictEqual(typeof async.nextTick, 'function'); 42 | assert.notStrictEqual(async.nextTick, process.nextTick); 43 | assert.strictEqual(async.nextTick, setImmediate); 44 | async.nextTick(done); 45 | }); 46 | 47 | it('should create original nextTick when process does not have nextTick and setImmediate', function(done) { 48 | 49 | var context = { 50 | require: require, 51 | console: console, 52 | exports: exports, 53 | setTimeout: setTimeout 54 | }; 55 | vm.runInNewContext(fs.readFileSync(asyncPath), context); 56 | assert.strictEqual(typeof context.async.nextTick, 'function'); 57 | assert.notStrictEqual(context.async.nextTick, process.nextTick); 58 | context.async.nextTick(done); 59 | }); 60 | 61 | it('should create original nextTick when process does not have nextTick and setImmediate for coverage', function(done) { 62 | 63 | var _nextTick = process.nextTick; 64 | var _setImmediate = setImmediate; 65 | process.nextTick = undefined; 66 | setImmediate = undefined; 67 | delete(require.cache[asyncPath]); 68 | var async = require(asyncPath); 69 | process.nextTick = _nextTick; 70 | setImmediate = _setImmediate; 71 | assert.strictEqual(typeof async.nextTick, 'function'); 72 | assert.notStrictEqual(async.nextTick, process.nextTick); 73 | async.nextTick(done); 74 | }); 75 | 76 | it('should avoid node warning [v0.10.x only]', function(done) { 77 | 78 | var array = _.times(10000); 79 | var iterator = function(n, done) { 80 | done(); 81 | }; 82 | async.eachSeries(array, iterator, done); 83 | }); 84 | 85 | it('should pass extra arguments', function(done) { 86 | 87 | async.nextTick(function(a, b, c, d) { 88 | assert.strictEqual(a, 1); 89 | assert.strictEqual(b, 2); 90 | assert.strictEqual(c, 3); 91 | assert.strictEqual(d, undefined); 92 | done(); 93 | }, 1, 2, 3); 94 | }); 95 | }); 96 | 97 | parallel('#setImmediate', function() { 98 | 99 | 'use strict'; 100 | 101 | it('should create original setImmediate if does not have setImmediate', function(done) { 102 | 103 | var context = { 104 | require: require, 105 | console: console, 106 | exports: exports, 107 | setTimeout: setTimeout 108 | }; 109 | vm.runInNewContext(fs.readFileSync(asyncPath), context); 110 | assert.strictEqual(typeof context.async.nextTick, 'function'); 111 | assert.notStrictEqual(context.async.nextTick, process.nextTick); 112 | context.async.nextTick(done); 113 | }); 114 | 115 | it('should create original setImmediate if does not have setImmediate for coverage', function(done) { 116 | 117 | var _setImmediate = setImmediate; 118 | setImmediate = undefined; 119 | delete(require.cache[asyncPath]); 120 | var async = require(asyncPath); 121 | setImmediate = _setImmediate; 122 | assert.strictEqual(typeof async.setImmediate, 'function'); 123 | assert.notStrictEqual(async.setImmediate, process.nextTick); 124 | async.nextTick(done); 125 | }); 126 | 127 | it('should pass extra arguments', function(done) { 128 | 129 | var _setImmediate = setImmediate; 130 | setImmediate = undefined; 131 | delete(require.cache[asyncPath]); 132 | var async = require(asyncPath); 133 | setImmediate = _setImmediate; 134 | async.setImmediate(function(a, b, c, d) { 135 | assert.strictEqual(a, 1); 136 | assert.strictEqual(b, 2); 137 | assert.strictEqual(c, 3); 138 | assert.strictEqual(d, undefined); 139 | done(); 140 | }, 1, 2, 3); 141 | }); 142 | }); 143 | 144 | parallel('#check functions', function() { 145 | 146 | 'use strict'; 147 | 148 | it('should have async functions', function() { 149 | _.forOwn(require('async'), function(func, key) { 150 | assert.ok(async[key], key + ' wasn\'t found.'); 151 | }); 152 | }); 153 | }); 154 | 155 | parallel('#other', function() { 156 | 157 | 'use strict'; 158 | 159 | var path = require('path'); 160 | 161 | it('should check whether "async" is assigned to context', function() { 162 | 163 | var context = { 164 | require: require, 165 | console: console, 166 | exports: exports 167 | }; 168 | vm.runInNewContext(fs.readFileSync(path.resolve(__dirname, '../../lib/async.js')), context); 169 | assert.ok(context.async); 170 | _.forOwn(context.async, function(func, key) { 171 | assert.ok(async[key]); 172 | }); 173 | }); 174 | 175 | it('should check whether "neo_async" is assigned to context', function() { 176 | 177 | var context = { 178 | require: require, 179 | console: console, 180 | exports: exports, 181 | async: require('async') 182 | }; 183 | vm.runInNewContext(fs.readFileSync(path.resolve(__dirname, '../../lib/async.js')), context); 184 | assert.ok(context.neo_async); 185 | _.forOwn(context.neo_async, function(func, key) { 186 | assert.ok(async[key]); 187 | }); 188 | }); 189 | }); 190 | 191 | parallel('#default', function() { 192 | 193 | 'use strict'; 194 | 195 | it('should have same functions', function() { 196 | 197 | _.forOwn(async['default'], function(value, key) { 198 | assert.ok(async[key], key + ' wasn\'t found.'); 199 | }); 200 | }); 201 | }); 202 | 203 | parallel('#safe', function() { 204 | 205 | 'use strict'; 206 | 207 | it('should execute on asynchronous', function(done) { 208 | 209 | async.safe(); 210 | var sync = true; 211 | var collection = [1, 3, 2]; 212 | var iterator = function(value, key, callback) { 213 | // sync call 214 | callback(); 215 | }; 216 | 217 | async.eachSeries(collection, iterator, function(err) { 218 | if (err) { 219 | return done(err); 220 | } 221 | assert.strictEqual(sync, false); 222 | done(); 223 | }); 224 | sync = false; 225 | }); 226 | }); 227 | 228 | parallel('#fast', function() { 229 | 230 | 'use strict'; 231 | 232 | before(function() { 233 | async.fast(); 234 | }); 235 | 236 | after(function() { 237 | async.safe(); 238 | }); 239 | 240 | it('should execute on synchronous', function(done) { 241 | 242 | var sync = true; 243 | var collection = [1, 3, 2]; 244 | var iterator = function(value, key, callback) { 245 | // sync call 246 | callback(); 247 | }; 248 | 249 | async.eachSeries(collection, iterator, function(err) { 250 | if (err) { 251 | return done(err); 252 | } 253 | assert.strictEqual(sync, true); 254 | done(); 255 | }); 256 | sync = false; 257 | }); 258 | }); 259 | -------------------------------------------------------------------------------- /test/util.js: -------------------------------------------------------------------------------- 1 | /* global it, Map, Set, Promise */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var _it = typeof Symbol === 'function' ? it : it.skip; 7 | _it.only = 8 | _it.only || 9 | function skipOnly(key) { 10 | it.only(key); 11 | }; 12 | 13 | exports.it = _it; 14 | 15 | /** 16 | * for v0.10.x 17 | */ 18 | exports.Map = 19 | typeof Map === 'function' 20 | ? Map 21 | : (function() { 22 | function Map(arr) { 23 | this._data = arr || []; 24 | } 25 | Map.prototype.set = function(key, value) { 26 | this._data.push([key, value]); 27 | }; 28 | Map.prototype[global.Symbol.iterator] = function() { 29 | var self = this; 30 | return { 31 | next: function() { 32 | var data = self._data.shift(); 33 | return { 34 | value: data, 35 | done: data === undefined 36 | }; 37 | } 38 | }; 39 | }; 40 | Object.defineProperty(Map.prototype, 'size', { 41 | get: function() { 42 | return this._data.length; 43 | } 44 | }); 45 | return Map; 46 | })(); 47 | 48 | exports.Set = 49 | typeof Set === 'function' 50 | ? Set 51 | : (function() { 52 | function Set(arr) { 53 | this._data = arr || []; 54 | } 55 | Set.prototype.add = function(value) { 56 | this._data.push(value); 57 | }; 58 | Set.prototype[global.Symbol.iterator] = function() { 59 | var self = this; 60 | return { 61 | next: function() { 62 | var data = self._data.shift(); 63 | return { 64 | value: data, 65 | done: data === undefined 66 | }; 67 | } 68 | }; 69 | }; 70 | Object.defineProperty(Set.prototype, 'size', { 71 | get: function() { 72 | return this._data.length; 73 | } 74 | }); 75 | return Set; 76 | })(); 77 | 78 | exports.errorChecker = function(err) { 79 | assert.ok(err); 80 | assert.strictEqual(err.message, 'Callback was already called.'); 81 | }; 82 | 83 | exports.uncaughtExceptionHandler = function(func) { 84 | var handler = function(err) { 85 | func(err); 86 | process.removeListener('uncaughtException', handler); 87 | }; 88 | process.removeAllListeners('uncaughtException'); 89 | process.domain = null; 90 | process.on('uncaughtException', handler); 91 | }; 92 | 93 | exports.Promise = typeof Promise !== 'undefined' ? Promise : require('bluebird'); 94 | 95 | exports.makeGenerator = function*(arr) { 96 | var idx = 0; 97 | var len = arr.length; 98 | while (idx < len) { 99 | yield arr[idx++]; 100 | } 101 | }; 102 | -------------------------------------------------------------------------------- /test/utils/test.asyncify.js: -------------------------------------------------------------------------------- 1 | /* global it, describe */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var async = require('../../'); 7 | var delay = require('../config').delay; 8 | var util = require('../util'); 9 | 10 | describe('#asyncify', function() { 11 | 12 | it('should call a synchronous function asynchronously', function(done) { 13 | 14 | var test = { 15 | hoge: true 16 | }; 17 | var func = function() { 18 | return test; 19 | }; 20 | async.asyncify(func)(function(err, res) { 21 | if (err) { 22 | return done(err); 23 | } 24 | assert.strictEqual(res, test); 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should call a synchronous function which has a promise as a result', function(done) { 30 | 31 | var test = { 32 | hoge: true 33 | }; 34 | var func = function() { 35 | return util.Promise.resolve(test); 36 | }; 37 | async.asyncify(func)(function(err, res) { 38 | if (err) { 39 | return done(err); 40 | } 41 | assert.strictEqual(res, test); 42 | done(); 43 | }); 44 | }); 45 | 46 | it('should throw error', function(done) { 47 | 48 | var message = 'error'; 49 | var func = function() { 50 | throw new Error(message); 51 | }; 52 | async.asyncify(func)(function(err) { 53 | assert.ok(err); 54 | assert.strictEqual(err.message, message); 55 | done(); 56 | }); 57 | }); 58 | 59 | it('should throw error by promise', function(done) { 60 | 61 | var message = 'error'; 62 | var func = function() { 63 | return util.Promise.reject(new Error(message)); 64 | }; 65 | async.asyncify(func)(function(err) { 66 | assert.ok(err); 67 | assert.strictEqual(err.message, message); 68 | done(); 69 | }); 70 | }); 71 | 72 | it('should throw an uncaughtException instead of unhandledRejection', function(done) { 73 | 74 | var error = new Error('callback error'); 75 | util.uncaughtExceptionHandler(function(err) { 76 | assert.ok(err); 77 | assert.strictEqual(err, error); 78 | done(); 79 | }); 80 | var func = function() { 81 | return util.Promise.reject(new Error('error')); 82 | }; 83 | async.asyncify(func)(function(err) { 84 | assert.ok(err); 85 | throw error; 86 | }); 87 | }); 88 | 89 | it('should avoid TypeError if return object is null', function(done) { 90 | 91 | var func = function() { 92 | return null; 93 | }; 94 | async.asyncify(func)(function(err, res) { 95 | if (err) { 96 | return done(err); 97 | } 98 | assert.strictEqual(res, null); 99 | done(); 100 | }); 101 | }); 102 | 103 | it('should throw an error if reject is called', function(done) { 104 | 105 | var func = function(arg) { 106 | return util.Promise.reject(arg + ' rejected'); 107 | }; 108 | async.asyncify(func)('argument', function(err) { 109 | assert.ok(err); 110 | assert.strictEqual(err.message, 'argument rejected'); 111 | done(); 112 | }); 113 | }); 114 | 115 | it('should throw an error even if reject is called with null', function(done) { 116 | var func = function() { 117 | return util.Promise.reject(null); 118 | }; 119 | async.asyncify(func)(function(err) { 120 | assert.ok(err); 121 | assert.ok(err instanceof Error); 122 | assert.strictEqual(err.message, 'null'); 123 | done(); 124 | }); 125 | }); 126 | 127 | it('should avoid double callback', function(done) { 128 | 129 | var count = 0; 130 | var msg = 'error in callback'; 131 | util.uncaughtExceptionHandler(function(err) { 132 | assert.ok(err); 133 | assert.strictEqual(err.message, msg); 134 | }); 135 | var promisified = function(arg) { 136 | return new util.Promise(function(resolve) { 137 | resolve(arg + ' resolved'); 138 | }); 139 | }; 140 | async.asyncify(promisified)('arg', function(err, res) { 141 | count++; 142 | if (err) { 143 | return done(err); 144 | } 145 | assert.strictEqual(res, 'arg resolved'); 146 | setTimeout(function() { 147 | assert.strictEqual(count, 1); 148 | done(); 149 | }, delay); 150 | throw new Error(msg); 151 | }); 152 | }); 153 | }); 154 | -------------------------------------------------------------------------------- /test/utils/test.constant.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#constant', function() { 11 | 12 | it('should get constant response', function(done) { 13 | async.constant(1, 2, 3)(function(err, result1, result2, result3) { 14 | if (err) { 15 | return done(err); 16 | } 17 | assert.deepStrictEqual(result1, 1); 18 | assert.deepStrictEqual(result2, 2); 19 | assert.deepStrictEqual(result3, 3); 20 | done(); 21 | }); 22 | }); 23 | 24 | it('should ignore other arguments', function(done) { 25 | async.constant(1, 2, 3)(4, 5, 6, 7, function(err, result1, result2, result3) { 26 | if (err) { 27 | return done(err); 28 | } 29 | assert.deepStrictEqual(result1, 1); 30 | assert.deepStrictEqual(result2, 2); 31 | assert.deepStrictEqual(result3, 3); 32 | assert.strictEqual(arguments.length, 4); 33 | done(); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/utils/test.createLogger.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#createLogger', function() { 11 | 12 | it('should test logger', function(done) { 13 | 14 | var fn = function(name) { 15 | 16 | return function(arg, callback) { 17 | 18 | assert.equal(arg, name); 19 | callback(null, name); 20 | }; 21 | }; 22 | 23 | var names = ['log', 'dir', 'test']; 24 | var name = names.shift(); 25 | var logger = async.createLogger(name); 26 | 27 | logger(fn(name), name, function(err, res) { 28 | if (err) { 29 | return done(err); 30 | } 31 | 32 | assert.equal(res, 'log'); 33 | name = names.shift(); 34 | logger = async.createLogger(name); 35 | 36 | logger(fn(name), name, function(err, res) { 37 | if (err) { 38 | return done(err); 39 | } 40 | 41 | assert.equal(res, 'dir'); 42 | name = names.shift(); 43 | logger = async.createLogger(name); 44 | 45 | logger(fn(name), name, function(err, res) { 46 | if (err) { 47 | return done(err); 48 | } 49 | 50 | assert.equal(res, 'test'); 51 | done(); 52 | }); 53 | }); 54 | }); 55 | 56 | }); 57 | 58 | it('should throw error', function(done) { 59 | 60 | var fn = function(name) { 61 | 62 | return function(arg, done, logger) { 63 | 64 | assert.equal(arg, name); 65 | logger('error'); 66 | done('error'); 67 | }; 68 | }; 69 | 70 | var names = ['log', 'debug', 'info']; 71 | var name = names.shift(); 72 | var logger = async.createLogger(name); 73 | 74 | logger(fn(name), name, function(err) { 75 | assert.ok(err); 76 | done(); 77 | }); 78 | 79 | }); 80 | 81 | it('should check logger', function(done) { 82 | 83 | var fn = function(arg, callback) { 84 | assert.strictEqual(arg, 'test'); 85 | callback(null, 'log', 'test'); 86 | done(); 87 | }; 88 | var logger = async.createLogger('warn'); 89 | logger(fn, 'test'); 90 | }); 91 | 92 | }); 93 | -------------------------------------------------------------------------------- /test/utils/test.ensureAsync.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#ensureAsync', function() { 11 | 12 | it('should call function on asynchronous even if funcion is called on synchronous', function(done) { 13 | 14 | var sync = true; 15 | var func = function(callback) { 16 | callback(); 17 | }; 18 | async.ensureAsync(func)(function(err) { 19 | if (err) { 20 | return done(err); 21 | } 22 | assert.strictEqual(sync, false); 23 | done(); 24 | }); 25 | sync = false; 26 | }); 27 | 28 | it('should call asynchronous function', function(done) { 29 | 30 | var sync = true; 31 | var func = function(callback) { 32 | setImmediate(callback); 33 | }; 34 | async.ensureAsync(func)(function(err) { 35 | if (err) { 36 | return done(err); 37 | } 38 | assert.strictEqual(sync, false); 39 | done(); 40 | }); 41 | sync = false; 42 | }); 43 | 44 | it('should bind context', function(done) { 45 | 46 | var func = function(callback) { 47 | callback(this); 48 | }; 49 | var newFunc = async.ensureAsync(func); 50 | newFunc = newFunc.bind(Math); 51 | newFunc(function(res) { 52 | assert.strictEqual(res, Math); 53 | done(); 54 | }); 55 | }); 56 | 57 | it('should not override the bound context of function', function(done) { 58 | 59 | var func = function(callback) { 60 | callback(this); 61 | }; 62 | var newFunc = func.bind(Math); 63 | newFunc = async.ensureAsync(newFunc); 64 | newFunc(function(res) { 65 | assert.strictEqual(res, Math); 66 | done(); 67 | }); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /test/utils/test.memoize.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#memoize', function() { 11 | 12 | it('should callback memo if same arguments', function(done) { 13 | 14 | var order = []; 15 | var fn = function(arg, callback) { 16 | order.push(arg); 17 | callback(); 18 | }; 19 | 20 | var fn2 = async.memoize(fn); 21 | 22 | fn2(1, function() { 23 | 24 | fn2(2, function() { 25 | 26 | fn2(1, function() { 27 | 28 | assert.deepStrictEqual(order, [1, 2]); 29 | done(); 30 | }); 31 | }); 32 | }); 33 | }); 34 | 35 | it('should callback memo and maintain asynchrony', function(done) { 36 | 37 | var order = []; 38 | var fn = function(arg1, arg2, callback) { 39 | order.push(['fn', arg1, arg2]); 40 | async.setImmediate(function() { 41 | order.push(['cb', arg1, arg2]); 42 | callback(null, arg1 + arg2); 43 | }); 44 | }; 45 | 46 | var fn2 = async.memoize(fn); 47 | 48 | fn2(1, 2, function(err, res) { 49 | assert.equal(res, 3); 50 | fn2(1, 2, function(err, res) { 51 | assert.equal(res, 3); 52 | async.nextTick(memoize_done); 53 | order.push('tick3'); 54 | }); 55 | order.push('tick2'); 56 | }); 57 | order.push('tick1'); 58 | 59 | function memoize_done() { 60 | 61 | var call_order = [ 62 | ['fn', 1, 2], 63 | 'tick1', ['cb', 1, 2], 64 | // ['fn', 1, 2], memoized 65 | 'tick2', 66 | // ['cb', 1, 2], memoized 67 | 'tick3' 68 | ]; 69 | assert.deepStrictEqual(call_order, order); 70 | done(); 71 | } 72 | 73 | }); 74 | 75 | it('should use queue', function(done) { 76 | 77 | var order = []; 78 | var fn = function(arg, callback) { 79 | order.push(arg); 80 | setTimeout(function() { 81 | callback(null, arg); 82 | }, 100); 83 | }; 84 | 85 | var fn2 = async.memoize(fn); 86 | fn2(1, function(err, res) { 87 | assert.ok(!err); 88 | assert.strictEqual(res, 1); 89 | }); 90 | fn2(2, function(err, res) { 91 | assert.ok(!err); 92 | assert.strictEqual(res, 2); 93 | }); 94 | fn2(1, function(err, res) { 95 | assert.ok(!err); 96 | assert.strictEqual(res, 1); 97 | }); 98 | setTimeout(function() { 99 | assert.deepStrictEqual(order, [1, 2]); 100 | done(); 101 | }, 300); 102 | 103 | }); 104 | 105 | it('should not memoize result if error occurs', function(done) { 106 | 107 | var called = 0; 108 | var order = []; 109 | var error = new Error('error'); 110 | var fn = function(arg, callback) { 111 | called++; 112 | callback(error, arg); 113 | }; 114 | var memoized = async.memoize(fn); 115 | memoized(1, function(err) { 116 | assert.strictEqual(err, error); 117 | error = null; 118 | memoized(1, function(err, result) { 119 | assert.strictEqual(err, null); 120 | assert.strictEqual(result, 1); 121 | assert.strictEqual(called, 2); 122 | done(); 123 | }); 124 | }) 125 | }); 126 | 127 | }); 128 | -------------------------------------------------------------------------------- /test/utils/test.reflect.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#reflect', function() { 11 | 12 | it('should execute with error in parallel', function(done) { 13 | 14 | var tasks = [ 15 | async.reflect(function(callback) { 16 | callback('error', 1); 17 | }), 18 | async.reflect(function(callback) { 19 | callback('error2', 2); 20 | }), 21 | async.reflect(function(callback) { 22 | callback(null, 3); 23 | }) 24 | ]; 25 | async.parallel(tasks, function(err, res) { 26 | if (err) { 27 | return done(err); 28 | } 29 | assert.deepStrictEqual(res, [ 30 | { error: 'error' }, 31 | { error: 'error2' }, 32 | { value: 3 } 33 | ]); 34 | done(); 35 | }); 36 | }); 37 | 38 | it('should execute with error in series', function(done) { 39 | 40 | var tasks = [ 41 | async.reflect(function(callback) { 42 | callback('error', 1); 43 | }), 44 | async.reflect(function(callback) { 45 | callback('error2', 2); 46 | }), 47 | async.reflect(function(callback) { 48 | callback(null, 3, 3); 49 | }) 50 | ]; 51 | async.series(tasks, function(err, res) { 52 | if (err) { 53 | return done(err); 54 | } 55 | assert.deepStrictEqual(res, [ 56 | { error: 'error' }, 57 | { error: 'error2' }, 58 | { value: [3, 3] } 59 | ]); 60 | done(); 61 | }); 62 | }); 63 | 64 | it('should execute even if it has an argument', function(done) { 65 | 66 | var reflect = async.reflect(function(arg, callback) { 67 | callback('error', arg); 68 | }); 69 | reflect(1, function(err, res) { 70 | if (err) { 71 | return done(err); 72 | } 73 | assert.deepStrictEqual(res, { 74 | error: 'error' 75 | }); 76 | done(); 77 | }); 78 | }); 79 | 80 | it('should execute even if it has two arguments', function(done) { 81 | 82 | var reflect = async.reflect(function(arg1, arg2, callback) { 83 | callback(null, arg1, arg2); 84 | }); 85 | reflect(1, 2, function(err, res) { 86 | if (err) { 87 | return done(err); 88 | } 89 | assert.deepStrictEqual(res, { 90 | value: [1, 2] 91 | }); 92 | done(); 93 | }); 94 | }); 95 | 96 | it('should execute even if it has some arguments', function(done) { 97 | 98 | var reflect = async.reflect(function(arg1, arg2, arg3, arg4, callback) { 99 | callback(null, arg3, arg4, arg1); 100 | }); 101 | reflect(1, 2, 3, 4, function(err, res) { 102 | if (err) { 103 | return done(err); 104 | } 105 | assert.deepStrictEqual(res, { 106 | value: [3, 4, 1] 107 | }); 108 | done(); 109 | }); 110 | }); 111 | }); 112 | 113 | parallel('#reflectAll', function() { 114 | 115 | it('should execute array tasks', function(done) { 116 | var tasks = [ 117 | function(done) { 118 | done('error', 1); 119 | }, 120 | function(done) { 121 | done('error2', 2); 122 | }, 123 | function(done) { 124 | done(null, 3); 125 | } 126 | ]; 127 | async.parallel(async.reflectAll(tasks), function(err, res) { 128 | if (err) { 129 | return done(err); 130 | } 131 | assert.deepStrictEqual(res, [ 132 | { error: 'error' }, 133 | { error: 'error2' }, 134 | { value: 3 } 135 | ]); 136 | done(); 137 | }); 138 | }); 139 | 140 | it('should execute object tasks', function(done) { 141 | var tasks = { 142 | a: function(done) { 143 | done('error', 1); 144 | }, 145 | b: function(done) { 146 | done('error2', 2); 147 | }, 148 | c: function(done) { 149 | done(null, 3, 4, 5); 150 | } 151 | }; 152 | async.parallel(async.reflectAll(tasks), function(err, res) { 153 | if (err) { 154 | return done(err); 155 | } 156 | assert.deepStrictEqual(res, { 157 | a: { error: 'error' }, 158 | b: { error: 'error2' }, 159 | c: { value: [3, 4, 5] } 160 | }); 161 | done(); 162 | }); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /test/utils/test.unmemoize.js: -------------------------------------------------------------------------------- 1 | /* global it */ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | var parallel = require('mocha.parallel'); 7 | 8 | var async = require('../../'); 9 | 10 | parallel('#unmemoize', function() { 11 | 12 | it('should execute without memo', function(done) { 13 | 14 | var order = []; 15 | var fn = function(arg, callback) { 16 | order.push(arg); 17 | callback(); 18 | }; 19 | 20 | var fn2 = async.memoize(fn); 21 | fn2 = async.unmemoize(fn2); 22 | 23 | fn2(1, function() { 24 | 25 | fn2(2, function() { 26 | 27 | fn2(1, function() { 28 | 29 | assert.deepStrictEqual(order, [1, 2, 1]); 30 | done(); 31 | }); 32 | }); 33 | }); 34 | }); 35 | 36 | }); 37 | --------------------------------------------------------------------------------