├── .gitattributes ├── .gitignore ├── .npmignore ├── README.md ├── aa.js ├── aa01.js ├── aa02.js ├── draft ├── aa-diff.js ├── aa02-test1.js ├── promise-diff.js ├── thunkify-new.js ├── thunkify-old.js ├── thunkify-test.cmd ├── thunkify-test.js ├── thunkify-timer-test.js └── thunkify.js ├── examples ├── aa-ex.js ├── aa-generator-ex.js ├── aa-generator-function-ex.js ├── aa-readme-ex01-seq.js ├── aa-readme-ex02-par.js ├── aa-readme-ex11-promisify.js ├── aa-readme-ex12-thunkify.js ├── aa-readme-example.js ├── aa-test.js ├── aa02-http-server.js ├── aa2.js ├── my-inspect.js ├── thunkify-work-main.js ├── thunkify-work-main2.js ├── tree-aa.js ├── tree-async.js ├── tree-sync.js └── tree.js ├── lib ├── chan.js └── trace.js ├── package.json ├── test ├── aa-readme-test.js └── aa02-readme-test.js └── tools ├── npm-publish.cmd ├── npm-publish.js └── release.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | 217 | ############# 218 | ## Node.js 219 | ############# 220 | 221 | node_modules/ 222 | 223 | *コピー* 224 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | .npm* 3 | examples/ 4 | lib/ 5 | test/ 6 | work/ 7 | draft/ 8 | tools/ 9 | images/ 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [aa](https://www.npmjs.com/package/aa) - [async-await](https://www.npmjs.com/package/async-await) 2 | ==== 3 | 4 | [![Join the chat at https://gitter.im/LightSpeedWorks/async-await](https://badges.gitter.im/LightSpeedWorks/async-await.svg)](https://gitter.im/LightSpeedWorks/async-await?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | co like library, go like channel, thunkify or promisify wrap package. 7 | 8 | using ES6 (ES2015) generator function. 9 | 10 | compatible with co@3 and co@4. 11 | 12 | 13 | INSTALL: 14 | ---- 15 | 16 | ```bash 17 | $ npm install aa --save 18 | or 19 | $ npm install async-await --save 20 | ``` 21 | 22 | [![NPM](https://nodei.co/npm/aa.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/aa/) 23 | [![NPM](https://nodei.co/npm-dl/aa.png?height=2)](https://nodei.co/npm/aa/) 24 | [![NPM](https://nodei.co/npm/async-await.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/async-await/) 25 | [![NPM](https://nodei.co/npm-dl/async-await.png?height=2)](https://nodei.co/npm/async-await/) 26 | 27 | 28 | PREPARE: 29 | ---- 30 | 31 | ```js 32 | var aa = require('aa'); 33 | // or 34 | var aa = require('async-await'); 35 | 36 | var promisify = aa.promisify; 37 | var thunkify = aa.thunkify; 38 | var promisifyAll = aa.promisifyAll; 39 | var thunkifyAll = aa.thunkifyAll; 40 | var Channel = aa.Channel; 41 | 42 | var Promise = aa.Promise; // override native Promise 43 | var PromiseThunk = aa.PromiseThunk; // use PromiseThunk indivisually 44 | ``` 45 | 46 | or 47 | 48 | https://lightspeedworks.github.io/promise-thunk/promise-thunk.js
49 | https://lightspeedworks.github.io/aa/aa.js 50 | 51 | ```html 52 | 53 | 54 | ``` 55 | 56 | USAGE: 57 | ---- 58 | 59 | ### aa(generator or generator function) 60 | 61 | `aa()` returns promise (thunkified promise). 62 | 63 | basic usage.
64 | you can `aa()` promises, generators, and generator functions. 65 | 66 | ```js 67 | aa(function *() { 68 | // *** SEQUENTIAL EXECUTION *** 69 | 70 | // yield value returns itself 71 | yiled 1; 72 | yiled [1, 2, 3]; 73 | yiled {x:1, y:2, z:3}; 74 | 75 | // yield promise returns resolved value 76 | yield Promise.resolve(1); 77 | 78 | // or throws rejected error 79 | try { yield Promise.reject(new Error('expected')); } 80 | catch (e) { console.error('%s', e); } 81 | 82 | // *** PARALLEL EXECUTION *** 83 | 84 | // yield an array of promises waits all promises and returns resolved array 85 | yield [Promise.resolve(1), Promise.resolve(2)]; 86 | 87 | // yield an object of promises waits all promises and returns resolved object 88 | yield {x: Promise.resolve(1), y: Promise.resolve(2)}; 89 | 90 | // *** OTHERS AND COMBINED OPERATIONS *** 91 | 92 | // yield thunk 93 | // yield generator or generator function 94 | // yield channel for event stream 95 | }); 96 | ``` 97 | 98 | 99 | ### aa.promisify([ctx,] fn, [options]) 100 | 101 | `promisify()` converts node style function into a function returns promise-thunk.
102 | you can use `fs.exists()` and `child_process.exec()` also. 103 | 104 | + `ctx`: context object. default: this or undefined. 105 | + `fn`: node-style normal function. 106 | + `options`: options object. 107 | + `context`: context object. 108 | 109 | also thenable, yieldable, callable. 110 | 111 | #### postgres `pg` example: 112 | 113 | ```js 114 | var pg = require('pg'); 115 | var pg_connect = aa.promisify(pg, pg.connect); // -> yield pg_connect() 116 | var client_query = aa.promisify(client, client.query); // -> yield client_query() 117 | ``` 118 | 119 | ### aa.promisify(object, method, [options]) 120 | 121 | `promisify()` defines method promisified function returns promise-thunk. 122 | 123 | + `object`: target object. 124 | + `method`: method name string. 125 | + `options`: method name suffix or postfix. default: 'Async'. or options object. 126 | + `suffix`: method name suffix or postfix. default: 'Async'. 127 | + `postfix`: method name suffix or postfix. default: 'Async'. 128 | 129 | #### postgres `pg` example: 130 | 131 | ```js 132 | var pg = require('pg'); 133 | aa.promisify(pg, 'connect', {suffix: 'A'}; // -> yield pg.connectA() 134 | aa.promisify(pg.Client.prototype, 'connect'); // -> yield client.connectAsync() 135 | aa.promisify(pg.Client.prototype, 'query'); // -> yield client.queryAsync() 136 | ``` 137 | 138 | ### aa.promisifyAll(object, [options]) 139 | 140 | `promisifyAll()` defines all methods promisified function returns promise-thunk. 141 | 142 | + `object`: target object. 143 | + `options`: method name suffix or postfix. default: 'Async'. or options object. 144 | + `suffix`: method name suffix or postfix. default: 'Async'. 145 | + `postfix`: method name suffix or postfix. default: 'Async'. 146 | 147 | #### file system `fs` example: 148 | 149 | ```js 150 | var fs = require('fs'); 151 | aa.promisifyAll(fs, {suffix: 'A'}); // -> yield fs.readFileA() 152 | ``` 153 | 154 | #### postgres `pg` example: 155 | 156 | ```js 157 | var pg = require('pg'); 158 | aa.promisifyAll(pg.constructor.prototype, {suffix: 'A'}); // -> yield pg.connectA() 159 | aa.promisifyAll(pg.Client.prototype); // -> yield client.connectAsync() 160 | // -> yield client.queryAsync() 161 | ``` 162 | 163 | ### aa.thunkify([ctx,] fn, [options]) 164 | 165 | `thunkify()` converts node style function into a thunkified function.
166 | you can use `fs.exists()` and `child_process.exec()` also. 167 | 168 | + `ctx`: context object. default: this or undefined. 169 | + `fn`: node-style normal function with callback. 170 | + `options`: options object. 171 | + `context`: context object. 172 | 173 | also yieldable, callable. 174 | 175 | #### postgres `pg` example: 176 | 177 | ```js 178 | var pg = require('pg'); 179 | var pg_connect = aa.thunkify(pg, pg.connect); // -> yield pg_connect() 180 | var client_query = aa.thunkify(client, client.query); // -> yield client_query() 181 | ``` 182 | 183 | ### aa.thunkify(object, method, [options]) 184 | 185 | `thunkify()` defines method thunkified function returns thunk. 186 | 187 | + `object`: target object. 188 | + `method`: method name string. 189 | + `options`: method name suffix or postfix. default: 'Async'. or options object. 190 | + `suffix`: method name suffix or postfix. default: 'Async'. 191 | + `postfix`: method name suffix or postfix. default: 'Async'. 192 | 193 | #### postgres `pg` example: 194 | 195 | ```js 196 | var pg = require('pg'); 197 | aa.thunkify(pg, 'connect', {suffix: 'A'}); // -> yield pg.connectA() 198 | aa.thunkify(pg.Client.prototype, 'connect'); // -> yield client.connectAsync() 199 | aa.thunkify(pg.Client.prototype, 'query'); // -> yield client.queryAsync() 200 | ``` 201 | 202 | ### aa.thunkifyAll(object, [options]) 203 | 204 | `thunkifyAll()` defines all methods thunkified function returns thunk. 205 | 206 | + `object`: target object. 207 | + `options`: method name suffix or postfix. default: 'Async'. or options object. 208 | + `suffix`: method name suffix or postfix. default: 'Async'. 209 | + `postfix`: method name suffix or postfix. default: 'Async'. 210 | 211 | #### file system `fs` example: 212 | 213 | ```js 214 | var fs = require('fs'); 215 | aa.thunkifyAll(fs, {suffix: 'A'}); // -> yield fs.readFileA() 216 | ``` 217 | 218 | #### postgres `pg` example: 219 | 220 | ```js 221 | var pg = require('pg'); 222 | aa.thunkifyAll(pg.constructor.prototype, {suffix: 'A'}); // -> yield pg.connectA() 223 | aa.thunkifyAll(pg.Client.prototype); // -> yield client.connectAsync() 224 | // -> yield client.queryAsync() 225 | ``` 226 | 227 | ### aa.Channel() : new channel for event stream 228 | 229 | `Channel()` returns a new channel for event stream.
230 | use a channel for node style function as a callback.
231 | yield channel for wait it.
232 | 233 | 234 | ### yield : waits and returns resolved value. 235 | 236 | you can `yield` promises, thunkified functions, 237 | generators, generator functions, 238 | primitive values, arrays, and objects.
239 | 240 | 241 | ### aa.callback(gtor) : returns callback function 242 | 243 | `callback(gtor)` returns normal callback function 244 | 245 | ```js 246 | http.createServer(aa.callback(function *(req, res) { 247 | yield aa.wait(1000); 248 | res.end('delayed hello'); 249 | })).listen(process.env.PORT || 8000); 250 | ``` 251 | 252 | EXAMPLES: 253 | ---- 254 | 255 | ### Example 1 sequential: [aa-readme-ex01-seq.js](examples/aa-readme-ex01-seq.js#readme) 256 | 257 | ```bash 258 | $ node aa-readme-ex01-seq.js 259 | ``` 260 | 261 | ```js 262 | var aa = require('aa'); 263 | 264 | 265 | aa(main); 266 | 267 | 268 | function *main() { 269 | console.log('11:', yield asyncPromise(100, 11)); 270 | console.log('12:', yield asyncThunk(100, 12)); 271 | console.log('13:', yield asyncGenerator(100, 13)); 272 | yield sub(20); 273 | yield sub(30); 274 | } 275 | 276 | 277 | function *sub(base) { 278 | console.log('%s: %s', base + 1, yield asyncPromise(100, base + 1)); 279 | console.log('%s: %s', base + 2, yield asyncThunk(100, base + 2)); 280 | console.log('%s: %s', base + 3, yield asyncGenerator(100, base + 3)); 281 | } 282 | 283 | 284 | // asyncPromise(msec, arg) : promise 285 | function asyncPromise(msec, arg) { 286 | return new Promise(function (resolve, reject) { 287 | setTimeout(resolve, msec, arg); 288 | }); 289 | } 290 | 291 | 292 | // asyncThunk(msec, arg) : thunk 293 | function asyncThunk(msec, arg) { 294 | return function (callback) { 295 | setTimeout(callback, msec, null, arg); 296 | }; 297 | } 298 | 299 | 300 | // asyncGenerator(msec, arg) : generator 301 | function *asyncGenerator(msec, arg) { 302 | var chan = aa.Channel(); 303 | setTimeout(chan, msec, arg); 304 | return yield chan; 305 | } 306 | ``` 307 | 308 | 309 | ### Example 2 parallel: [aa-readme-ex02-par.js](examples/aa-readme-ex02-par.js#readme) 310 | 311 | ```bash 312 | $ node aa-readme-ex02-par.js 313 | ``` 314 | 315 | ```js 316 | var aa = require('aa'); 317 | 318 | 319 | aa(main); 320 | 321 | 322 | function *main() { 323 | console.log('[11, 12, 13]:', yield [ 324 | asyncPromise(100, 11), 325 | asyncThunk(100, 12), 326 | asyncGenerator(100, 13) 327 | ]); 328 | 329 | console.log('{x:11, y:12, z:13}:', yield { 330 | x: asyncPromise(100, 11), 331 | y: asyncThunk(100, 12), 332 | z: asyncGenerator(100, 13) 333 | }); 334 | 335 | yield [sub(20), sub(30)]; 336 | } 337 | 338 | 339 | function *sub(base) { 340 | console.log('%s: %s', base + 1, yield asyncPromise(100, base + 1)); 341 | console.log('%s: %s', base + 2, yield asyncThunk(100, base + 2)); 342 | console.log('%s: %s', base + 3, yield asyncGenerator(100, base + 3)); 343 | } 344 | 345 | 346 | // asyncPromise(msec, arg) : promise 347 | function asyncPromise(msec, arg) { 348 | return new Promise(function (resolve, reject) { 349 | setTimeout(resolve, msec, arg); 350 | }); 351 | } 352 | 353 | 354 | // asyncThunk(msec, arg) : thunk 355 | function asyncThunk(msec, arg) { 356 | return function (callback) { 357 | setTimeout(callback, msec, null, arg); 358 | }; 359 | } 360 | 361 | 362 | // asyncGenerator(msec, arg) : generator 363 | function *asyncGenerator(msec, arg) { 364 | var chan = aa.Channel(); 365 | setTimeout(chan, msec, arg); 366 | return yield chan; 367 | } 368 | ``` 369 | 370 | 371 | ### Example promisify: [aa-readme-ex11-promisify.js](examples/aa-readme-ex11-promisify.js#readme) 372 | 373 | ```bash 374 | $ node aa-readme-ex11-promisify.js 375 | ``` 376 | 377 | ```js 378 | var aa = require('aa'); 379 | var promisify = aa.promisify; 380 | var asyncPromise = promisify(asyncCallback); 381 | 382 | 383 | aa(main); 384 | 385 | 386 | function *main() { 387 | console.log('11:', yield asyncPromise(100, 11)); 388 | console.log('12:', yield asyncPromise(100, 12)); 389 | console.log('13:', yield asyncPromise(100, 13)); 390 | 391 | asyncPromise(100, 21) 392 | .then(function (val) { 393 | console.log('21:', val); 394 | return asyncPromise(100, 22); 395 | }) 396 | .then(function (val) { 397 | console.log('22:', val); 398 | return asyncPromise(100, 23); 399 | }) 400 | .then(function (val) { 401 | console.log('23:', val); 402 | }); 403 | } 404 | 405 | 406 | // asyncCallback(msec, arg. callback) : node style normal callback 407 | // callback : function (err, val) 408 | function asyncCallback(msec, arg, callback) { 409 | setTimeout(callback, msec, null, arg); 410 | } 411 | ``` 412 | 413 | 414 | ### Example thunkify: [aa-readme-ex12-thunkify.js](examples/aa-readme-ex12-thunkify.js#readme) 415 | 416 | ```bash 417 | $ node aa-readme-ex12-thunkify.js 418 | ``` 419 | 420 | ```js 421 | var aa = require('aa'); 422 | var thunkify = aa.thunkify; 423 | var asyncThunk = thunkify(asyncCallback); 424 | 425 | 426 | aa(main); 427 | 428 | 429 | function *main() { 430 | console.log('11:', yield asyncThunk(100, 11)); 431 | console.log('12:', yield asyncThunk(100, 12)); 432 | console.log('13:', yield asyncThunk(100, 13)); 433 | 434 | asyncThunk(100, 21) 435 | (function (err, val) { 436 | console.log('21:', val); 437 | asyncThunk(100, 22) 438 | (function (err, val) { 439 | console.log('22:', val); 440 | asyncThunk(100, 23) 441 | (function (err, val) { 442 | console.log('23:', val); 443 | }); 444 | }); 445 | }); 446 | } 447 | 448 | 449 | // asyncCallback(msec, arg. callback) : node style normal callback 450 | // callback : function (err, val) 451 | function asyncCallback(msec, arg, callback) { 452 | setTimeout(callback, msec, null, arg); 453 | } 454 | ``` 455 | 456 | 457 | ### Quick example collection: [aa-readme-example.js](examples/aa-readme-example.js#readme) 458 | 459 | ```bash 460 | $ node aa-readme-example.js 461 | ``` 462 | 463 | 464 | ```js 465 | var aa = require('aa'); 466 | 467 | 468 | // sleep(msec, args,... callback) : node style normal callback 469 | // callback : function (err, val) 470 | function sleep(msec) { 471 | var args = [].slice.call(arguments, 1); 472 | setTimeout.apply(null, [args.pop(), msec, null].concat(args)); 473 | } 474 | 475 | sleep(1000, function (err, val) { console.log('1000 msec OK'); }); 476 | 477 | 478 | // delay(msec, args,...)(callback) : thunk 479 | // callback : function (err, val) 480 | function delay(msec) { 481 | var args = [].slice.call(arguments); 482 | return function (callback) { 483 | sleep.apply(null, args.concat(callback)); 484 | }; 485 | } 486 | // var delay = aa.thunkify(sleep); 487 | 488 | delay(1100)( 489 | function (err, val) { console.log('1100 msec OK'); } 490 | ); 491 | 492 | 493 | // aa.promisify(fn) : returns wrapped function a.k.a thunkify and promisify 494 | // wait(msec, args,...) : returns promise & thunk 495 | var wait = aa.promisify(sleep); 496 | 497 | // wait() : as a thunk 498 | wait(1200)( 499 | function (err, val) { console.log('1200 msec OK'); } 500 | ); 501 | 502 | // wait() : as a promise 503 | wait(1300).then( 504 | function (val) { console.log('1300 msec OK'); }, 505 | function (err) { console.log('1300 msec NG', err); } 506 | ).catch( 507 | function (err) { console.log('1300 msec NG2', err); } 508 | ); 509 | 510 | 511 | // aa(generator) : returns promise & thunk 512 | aa(function *() { 513 | 514 | yield 1; // primitive value 515 | yield [1, 2, 3]; // array 516 | yield {x:1, y:2, z:3}; // object 517 | 518 | 519 | // wait for promise 520 | yield Promise.resolve(2); 521 | 522 | 523 | // wait for thunk 524 | yield delay(800); 525 | 526 | 527 | // wait for promise or thunk 528 | yield wait(800); 529 | 530 | 531 | console.log('0:', yield wait(300, 0)); 532 | console.log('1:', yield wait(300, 1)); 533 | 534 | 535 | // yield Promise.all([]) 536 | console.log('[1, 2, 3]:', 537 | yield Promise.all([wait(200, 1), wait(300, 2), wait(100, 3)])); 538 | 539 | 540 | // yield [] -> like Promise.all([]) ! 541 | console.log('[4, 5, 6]:', 542 | yield [wait(200, 4), wait(300, 5), wait(100, 6)]); 543 | 544 | 545 | // yield {} -> like Promise.all({}) !? 546 | console.log('{x:7, y:8, z:9}:', 547 | yield {x:wait(200, 7), y:wait(300, 8), z:wait(100, 9)}); 548 | 549 | 550 | // make channel for sync - fork and join 551 | var chan = aa.Channel(); 552 | 553 | sleep(300, 20, chan); // send value to channel : fork or spread 554 | sleep(200, 10, chan); // send value to channel : fork or spread 555 | var a = yield chan; // recv value from channel : join or sync 556 | var b = yield chan; // recv value from channel : join or sync 557 | console.log('10 20:', a, b); 558 | 559 | 560 | // fork thread - make new thread and start 561 | aa(function *() { 562 | yield wait(200); // wait 200 msec 563 | return 200; 564 | })(chan); // send 200 to channel : join or sync 565 | 566 | // fork thread - make new thread and start 567 | aa(function *() { 568 | yield wait(100); // wait 100 msec 569 | return 100; 570 | })(chan); // send 100 to channel : join or sync 571 | 572 | // fork thread - make new thread and start 573 | aa(function *() { 574 | yield wait(300); // wait 300 575 | return 300; 576 | })(chan); // send 300 to channel : join or sync 577 | 578 | // join threads - sync threads 579 | var x = yield chan; // wait & recv first value from channel 580 | var y = yield chan; // wait & recv second value from channel 581 | var z = yield chan; // wait & recv third value from channel 582 | console.log('top 3 winners: 100 200 300:', x, y, z); 583 | 584 | 585 | // communicate with channels 586 | var chan1 = aa.Channel(), chan2 = aa.Channel(); 587 | 588 | // thread 1: send to chan1, recv from chan2 589 | aa(function *() { 590 | sleep(100, 111, chan1); 591 | console.log('222:', yield chan2); 592 | sleep(100, 333, chan1); 593 | console.log('444:', yield chan2); 594 | sleep(100, 555, chan1); 595 | return 666; 596 | })(chan); 597 | 598 | // thread 1: recv from chan1, send to chan2 599 | aa(function *() { 600 | console.log('111:', yield chan1); 601 | sleep(100, 222, chan2); 602 | console.log('333:', yield chan1); 603 | sleep(100, 444, chan2); 604 | console.log('555:', yield chan1); 605 | return 777; 606 | })(chan); 607 | console.log('666 777:', yield chan, yield chan); 608 | 609 | return 11; 610 | }) 611 | .then( 612 | function (val) { 613 | console.log('11 val:', val); 614 | return wait(100, 22); }, 615 | function (err) { 616 | console.log('11 err:', err); 617 | return wait(100, 22); } 618 | ) 619 | (function (err, val) { 620 | console.log('22 val:', val, err ? 'err:' + err : ''); 621 | return wait(100, 33); }) 622 | (function (err, val) { 623 | console.log('33 val:', val, err ? 'err:' + err : ''); 624 | return wait(100, 44); }) 625 | .then( 626 | function (val) { 627 | console.log('44 val:', val); 628 | return wait(100, 55); }, 629 | function (err) { 630 | console.log('44 err:', err); 631 | return wait(100, 55); } 632 | ) 633 | .catch( 634 | function (err) { 635 | console.log('55 err:', err); 636 | return wait(100, 66); } 637 | ); 638 | ``` 639 | 640 | 641 | LICENSE: 642 | ---- 643 | 644 | MIT 645 | -------------------------------------------------------------------------------- /aa.js: -------------------------------------------------------------------------------- 1 | // aa.js - async-await.js 2 | 3 | this.aa = function (PromiseThunk) { 4 | 'use strict'; 5 | 6 | var isPromise = PromiseThunk.isPromise; 7 | var promisify = PromiseThunk.promisify; 8 | 9 | // GeneratorFunction 10 | try { 11 | var GeneratorFunction = Function('return function*(){}.constructor')(); 12 | } catch (e) {} 13 | 14 | // GeneratorFunctionPrototype 15 | try { 16 | var GeneratorFunctionPrototype = Function('return (function*(){})().constructor')(); 17 | } catch (e) {} 18 | 19 | var slice = [].slice; 20 | 21 | // defProp 22 | var defProp = function (obj) { 23 | if (!Object.defineProperty) return null; 24 | try { 25 | Object.defineProperty(obj, 'prop', {value: 'str'}); 26 | return obj.prop === 'str' ? Object.defineProperty : null; 27 | } catch (err) { return null; } 28 | } ({}); 29 | 30 | // setConst(obj, prop, val) 31 | var setConst = defProp ? 32 | function setConst(obj, prop, val) { 33 | defProp(obj, prop, {value: val}); } : 34 | function setConst(obj, prop, val) { obj[prop] = val; }; 35 | 36 | // setValue(obj, prop, val) 37 | var setValue = defProp ? 38 | function setValue(obj, prop, val) { 39 | defProp(obj, prop, {value: val, 40 | writable: true, configurable: true}); } : 41 | function setValue(obj, prop, val) { obj[prop] = val; }; 42 | 43 | // setProto(obj, proto) 44 | var setProto = Object.setPrototypeOf || {}.__proto__ ? 45 | function setProto(obj, proto) { obj.__proto__ = proto; } : null; 46 | 47 | 48 | // Queue 49 | function Queue() { 50 | this.tail = this.head = null; 51 | } 52 | Queue.prototype.push = function push(x) { 53 | if (this.tail) 54 | this.tail = this.tail[1] = [x, null]; 55 | else 56 | this.tail = this.head = [x, null]; 57 | }; 58 | Queue.prototype.shift = function shift() { 59 | if (!this.head) return null; 60 | var x = this.head[0]; 61 | this.head = this.head[1]; 62 | if (!this.head) this.tail = null; 63 | return x; 64 | }; 65 | 66 | 67 | // nextTickDo(fn) 68 | var nextTickDo = typeof setImmediate === 'function' ? setImmediate : 69 | typeof process === 'object' && process && typeof process.nextTick === 'function' ? process.nextTick : 70 | function nextTick(fn) { setTimeout(fn, 0); }; 71 | 72 | var tasks = new Queue(); 73 | 74 | var nextTickProgress = false; 75 | 76 | // nextTick(fn, ...args) 77 | function nextTick(fn) { 78 | if (typeof fn !== 'function') 79 | throw new TypeError('fn must be a function'); 80 | 81 | tasks.push(arguments); 82 | if (nextTickProgress) return; 83 | 84 | nextTickProgress = true; 85 | 86 | nextTickDo(function () { 87 | var args; 88 | while (args = tasks.shift()) 89 | args[0](args[1], args[2], args[3], args[4]); 90 | 91 | nextTickProgress = false; 92 | }); 93 | } 94 | 95 | 96 | // aa - async-await 97 | function aa(gtor) { 98 | var ctx = this, args = slice.call(arguments, 1); 99 | 100 | // is generator function? then get generator. 101 | if (isGeneratorFunction(gtor)) 102 | gtor = gtor.apply(ctx, args); 103 | 104 | // is promise? then do it. 105 | if (isPromise(gtor)) 106 | return PromiseThunk.resolve(gtor); 107 | 108 | // is function? then promisify it. 109 | if (typeof gtor === 'function') 110 | return promisify.call(ctx, gtor); 111 | 112 | // is not generator? 113 | if (!isGenerator(gtor)) 114 | return Channel.apply(ctx, arguments); 115 | 116 | var resolve, reject, p = new PromiseThunk( 117 | function (res, rej) { resolve = res; reject = rej; }); 118 | 119 | nextTick(callback); 120 | return p; 121 | 122 | function callback(err, val) { 123 | try { 124 | if (err) { 125 | if (typeof gtor['throw'] !== 'function') 126 | return reject(err); 127 | var ret = gtor['throw'](err); 128 | } 129 | else 130 | var ret = gtor.next(val); 131 | } catch (err) { 132 | return reject(err); 133 | } 134 | 135 | if (ret.done) 136 | return resolve(ret.value); 137 | 138 | nextTick(doValue, ret.value, callback, ctx, args); 139 | } 140 | 141 | } 142 | 143 | 144 | function doValue(value, callback, ctx, args) { 145 | if (value == null || 146 | typeof value !== 'object' && 147 | typeof value !== 'function') 148 | return callback(null, value); 149 | 150 | if (isGeneratorFunction(value)) 151 | value = value.apply(ctx, args); 152 | 153 | if (isGenerator(value)) 154 | return aa.call(ctx, value)(callback); 155 | 156 | // function must be a thunk 157 | if (typeof value === 'function') 158 | return value(callback); 159 | 160 | if (isPromise(value)) 161 | return value.then(function (val) { callback(null, val); }, callback); 162 | 163 | var called = false; 164 | 165 | // array 166 | if (value instanceof Array) { 167 | var n = value.length; 168 | if (n === 0) return callback(null, []); 169 | var arr = Array(n); 170 | value.forEach(function (val, i) { 171 | doValue(val, function (err, val) { 172 | if (err) { 173 | if (!called) 174 | called = true, callback(err); 175 | } 176 | else { 177 | arr[i] = val; 178 | if (--n === 0 && !called) 179 | called = true, callback(null, arr); 180 | } 181 | }); 182 | }); 183 | } // array 184 | 185 | // object 186 | else if (value.constructor === Object) { 187 | var keys = Object.keys(value); 188 | var n = keys.length; 189 | if (n === 0) return callback(null, {}); 190 | var obj = {}; 191 | keys.forEach(function (key) { 192 | obj[key] = undefined; 193 | doValue(value[key], function (err, val) { 194 | if (err) { 195 | if (!called) 196 | called = true, callback(err); 197 | } 198 | else { 199 | obj[key] = val; 200 | if (--n === 0 && !called) 201 | called = true, callback(null, obj); 202 | } 203 | }); 204 | }); 205 | } // object 206 | 207 | // other value 208 | else 209 | return callback(null, value); 210 | } 211 | 212 | 213 | // isGeneratorFunction 214 | function isGeneratorFunction(gtor) { 215 | if (!gtor) return false; 216 | var ctor = gtor.constructor; 217 | return ctor === GeneratorFunction || 218 | (ctor.displayName || ctor.name) === 'GeneratorFunction'; 219 | } 220 | 221 | // isGenerator 222 | function isGenerator(gtor) { 223 | if (!gtor) return false; 224 | var ctor = gtor.constructor; 225 | return ctor === GeneratorFunctionPrototype || 226 | (ctor.displayName || ctor.name) === 'GeneratorFunctionPrototype' || 227 | typeof gtor.next === 'function'; 228 | } 229 | 230 | 231 | // Channel(empty) 232 | // recv: chan(cb) 233 | // send: chan(err, data) 234 | // send: chan() or chan(undefined) 235 | // send: chan(data) 236 | // chan.end() 237 | // chan.empty 238 | // chan.done() 239 | // chan.send(val or err) 240 | // chan.recv(cb) 241 | 242 | if (setProto) 243 | setProto(Channel.prototype, Function.prototype); 244 | else { 245 | Channel.prototype = Function(); 246 | Channel.prototype.constructor = Channel; 247 | } 248 | 249 | 250 | // Channel(empty) 251 | function Channel(empty) { 252 | if (arguments.length > 1) 253 | throw new Error('Channel: too many arguments'); 254 | 255 | channel.$isClosed = false; // send stream is closed 256 | channel.$isDone = false; // receive stream is done 257 | channel.$recvCallbacks = []; // receive pending callbacks queue 258 | channel.$sendValues = []; // send pending values 259 | 260 | channel.empty = typeof empty === 'function' ? new empty() : empty; 261 | 262 | if (setProto) 263 | setProto(channel, Channel.prototype); 264 | else { 265 | channel.close = $$close; 266 | channel.done = $$done; 267 | channel.send = $$send; 268 | channel.recv = $$recv; 269 | 270 | // for stream 271 | channel.end = $$close; 272 | channel.stream = $$stream; 273 | 274 | if (channel.call !== Function.prototype.call) 275 | channel.call = Function.prototype.call; 276 | 277 | if (channel.apply !== Function.prototype.apply) 278 | channel.apply = Function.prototype.apply; 279 | } 280 | 281 | return channel; 282 | 283 | function channel(a, b) { 284 | // yield callback 285 | if (typeof a === 'function') 286 | return channel.recv(a); 287 | 288 | // error 289 | if (a instanceof Error) 290 | return channel.send(a); 291 | 292 | // value or undefined 293 | if (arguments.length <= 1) 294 | return channel.send(a); 295 | 296 | var args = slice.call(arguments); 297 | 298 | if (a == null) { 299 | if (arguments.length === 2) 300 | return channel.send(b); 301 | else 302 | args.shift(); 303 | } 304 | 305 | // (null, value,...) -> [value, ...] 306 | return channel.send(args); 307 | } 308 | 309 | } // Channel 310 | 311 | // send(val or err) 312 | var $$send = Channel.prototype.send = send; 313 | function send(val) { 314 | if (this.$isClosed) 315 | throw new Error('Cannot send to closed channel'); 316 | else if (this.$recvCallbacks.length > 0) 317 | complete(this.$recvCallbacks.shift(), val); 318 | else 319 | this.$sendValues.push(val); 320 | } // send 321 | 322 | // recv(cb) 323 | var $$recv = Channel.prototype.recv = recv; 324 | function recv(cb) { 325 | if (this.done()) 326 | cb(null, this.empty); 327 | else if (this.$sendValues.length > 0) 328 | complete(cb, this.$sendValues.shift()); 329 | else 330 | this.$recvCallbacks.push(cb); 331 | return; 332 | } // recv 333 | 334 | // done() 335 | var $$done = Channel.prototype.done = done; 336 | function done() { 337 | if (!this.$isDone && this.$isClosed && this.$sendValues.length === 0) { 338 | this.$isDone = true; 339 | // complete each pending callback with the empty value 340 | var empty = this.empty; 341 | this.$recvCallbacks.forEach(function(cb) { complete(cb, empty); }); 342 | } 343 | 344 | return this.$isDone; 345 | } // done 346 | 347 | // close() end() 348 | var $$close = Channel.prototype.close = Channel.prototype.end = close; 349 | function close() { 350 | this.$isClosed = true; 351 | return this.done(); 352 | } // close 353 | 354 | // stream(reader) 355 | var $$stream = Channel.prototype.stream = stream; 356 | function stream(reader) { 357 | var channel = this; 358 | reader.on('end', close); 359 | reader.on('error', error); 360 | reader.on('readable', readable); 361 | return this; 362 | 363 | function close() { return channel.close(); } 364 | function error(err) { try { channel.send(err); } catch (e) {} } 365 | 366 | function readable() { 367 | var buf = this.read(); 368 | if (!buf) return; 369 | try { channel.send(buf); } catch (e) {} 370 | } // readable 371 | } // stream 372 | 373 | // complete(cb, val or err) 374 | function complete(cb, val) { 375 | if (val instanceof Error) 376 | cb(val); 377 | else 378 | cb(null, val); 379 | } // complete 380 | 381 | 382 | // aa.wait(msec, val) 383 | function wait(msec, val) { 384 | return function (cb) { 385 | setTimeout(cb, msec, null, val); 386 | }; 387 | }; 388 | 389 | 390 | // aa.callback(gtor) 391 | aa.callback = function callback(gtor) { 392 | return function () { 393 | return aa(gtor.apply(this, arguments)); 394 | }; 395 | }; 396 | 397 | 398 | if (typeof module === 'object' && module && module.exports) 399 | module.exports = aa; 400 | 401 | if (GeneratorFunction) 402 | aa.GeneratorFunction = GeneratorFunction; 403 | 404 | aa.isGeneratorFunction = isGeneratorFunction; 405 | aa.isGenerator = isGenerator; 406 | aa.aa = aa; 407 | aa.chan = aa.Channel = Channel; 408 | aa.wait = wait; 409 | 410 | if (Object.getOwnPropertyNames) 411 | Object.getOwnPropertyNames(PromiseThunk).forEach(function (prop) { 412 | if (!aa.hasOwnProperty(prop)) 413 | setValue(aa, prop, PromiseThunk[prop]); 414 | }); 415 | else 416 | for (var prop in PromiseThunk) 417 | if (!aa.hasOwnProperty(prop)) 418 | setValue(aa, prop, PromiseThunk[prop]); 419 | 420 | return aa; 421 | 422 | }(this.PromiseThunk || require('promise-thunk')); 423 | -------------------------------------------------------------------------------- /aa01.js: -------------------------------------------------------------------------------- 1 | // aa.js - async-await.js 2 | 3 | this.aa = function (PromiseThunk) { 4 | 'use strict'; 5 | 6 | var isPromise = PromiseThunk.isPromise; 7 | var promisify = PromiseThunk.promisify; 8 | 9 | // GeneratorFunction 10 | try { 11 | var GeneratorFunction = Function('return function*(){}.constructor')(); 12 | } catch (e) {} 13 | 14 | // GeneratorFunctionPrototype 15 | try { 16 | var GeneratorFunctionPrototype = Function('return (function*(){})().constructor')(); 17 | } catch (e) {} 18 | 19 | var slice = [].slice; 20 | 21 | // defProp 22 | var defProp = function (obj) { 23 | if (!Object.defineProperty) return null; 24 | try { 25 | Object.defineProperty(obj, 'prop', {value: 'str'}); 26 | return obj.prop === 'str' ? Object.defineProperty : null; 27 | } catch (err) { return null; } 28 | } ({}); 29 | 30 | // setConst(obj, prop, val) 31 | var setConst = defProp ? 32 | function setConst(obj, prop, val) { 33 | defProp(obj, prop, {value: val}); } : 34 | function setConst(obj, prop, val) { obj[prop] = val; }; 35 | 36 | // setValue(obj, prop, val) 37 | var setValue = defProp ? 38 | function setValue(obj, prop, val) { 39 | defProp(obj, prop, {value: val, 40 | writable: true, configurable: true}); } : 41 | function setValue(obj, prop, val) { obj[prop] = val; }; 42 | 43 | // setProto(obj, proto) 44 | var setProto = Object.setPrototypeOf || {}.__proto__ ? 45 | function setProto(obj, proto) { obj.__proto__ = proto; } : null; 46 | 47 | 48 | // Queue 49 | function Queue() { 50 | this.tail = this.head = null; 51 | } 52 | Queue.prototype.push = function push(x) { 53 | if (this.tail) 54 | this.tail = this.tail[1] = [x, null]; 55 | else 56 | this.tail = this.head = [x, null]; 57 | }; 58 | Queue.prototype.shift = function shift() { 59 | if (!this.head) return null; 60 | var x = this.head[0]; 61 | this.head = this.head[1]; 62 | if (!this.head) this.tail = null; 63 | return x; 64 | }; 65 | 66 | 67 | // nextTickDo(fn) 68 | var nextTickDo = typeof setImmediate === 'function' ? setImmediate : 69 | typeof process === 'object' && process && typeof process.nextTick === 'function' ? process.nextTick : 70 | function nextTick(fn) { setTimeout(fn, 0); }; 71 | 72 | var tasks = new Queue(); 73 | 74 | var nextTickProgress = false; 75 | 76 | // nextTick(fn, ...args) 77 | function nextTick(fn) { 78 | if (typeof fn !== 'function') 79 | throw new TypeError('fn must be a function'); 80 | 81 | tasks.push(arguments); 82 | if (nextTickProgress) return; 83 | 84 | nextTickProgress = true; 85 | 86 | nextTickDo(function () { 87 | var args; 88 | while (args = tasks.shift()) 89 | args[0](args[1], args[2], args[3], args[4]); 90 | 91 | nextTickProgress = false; 92 | }); 93 | } 94 | 95 | 96 | // aa - async-await 97 | function aa(gtor) { 98 | var ctx = this, args = slice.call(arguments, 1); 99 | 100 | // is generator function? then get generator. 101 | if (isGeneratorFunction(gtor)) 102 | gtor = gtor.apply(ctx, args); 103 | 104 | // is promise? then do it. 105 | if (isPromise(gtor)) 106 | return PromiseThunk.resolve(gtor); 107 | 108 | // is function? then promisify it. 109 | if (typeof gtor === 'function') 110 | return promisify.call(ctx, gtor); 111 | 112 | // is not generator? 113 | if (!isGenerator(gtor)) 114 | return Channel.apply(ctx, arguments); 115 | 116 | var resolve, reject, p = new PromiseThunk( 117 | function (res, rej) { resolve = res; reject = rej; }); 118 | 119 | nextTick(callback); 120 | return p; 121 | 122 | function callback(err, val) { 123 | try { 124 | if (err) { 125 | if (typeof gtor['throw'] !== 'function') 126 | return reject(err); 127 | var ret = gtor['throw'](err); 128 | } 129 | else 130 | var ret = gtor.next(val); 131 | } catch (err) { 132 | return reject(err); 133 | } 134 | 135 | if (ret.done) 136 | return resolve(ret.value); 137 | 138 | nextTick(doValue, ret.value, callback, ctx, args); 139 | } 140 | 141 | } 142 | 143 | 144 | function doValue(value, callback, ctx, args) { 145 | if (value == null || 146 | typeof value !== 'object' && 147 | typeof value !== 'function') 148 | return callback(null, value); 149 | 150 | if (isGeneratorFunction(value)) 151 | value = value.apply(ctx, args); 152 | 153 | if (isGenerator(value)) 154 | return aa.call(ctx, value)(callback); 155 | 156 | // function must be a thunk 157 | if (typeof value === 'function') 158 | return value(callback); 159 | 160 | if (isPromise(value)) 161 | return value.then(function (val) { callback(null, val); }, callback); 162 | 163 | var called = false; 164 | 165 | // array 166 | if (value instanceof Array) { 167 | var n = value.length; 168 | if (n === 0) return callback(null, []); 169 | var arr = Array(n); 170 | value.forEach(function (val, i) { 171 | doValue(val, function (err, val) { 172 | if (err) { 173 | if (!called) 174 | called = true, callback(err); 175 | } 176 | else { 177 | arr[i] = val; 178 | if (--n === 0 && !called) 179 | called = true, callback(null, arr); 180 | } 181 | }); 182 | }); 183 | } // array 184 | 185 | // object 186 | else if (value.constructor === Object) { 187 | var keys = Object.keys(value); 188 | var n = keys.length; 189 | if (n === 0) return callback(null, {}); 190 | var obj = {}; 191 | keys.forEach(function (key) { 192 | obj[key] = undefined; 193 | doValue(value[key], function (err, val) { 194 | if (err) { 195 | if (!called) 196 | called = true, callback(err); 197 | } 198 | else { 199 | obj[key] = val; 200 | if (--n === 0 && !called) 201 | called = true, callback(null, obj); 202 | } 203 | }); 204 | }); 205 | } // object 206 | 207 | // other value 208 | else 209 | return callback(null, value); 210 | } 211 | 212 | 213 | // isGeneratorFunction 214 | function isGeneratorFunction(gtor) { 215 | if (!gtor) return false; 216 | var ctor = gtor.constructor; 217 | return ctor === GeneratorFunction || 218 | (ctor.displayName || ctor.name) === 'GeneratorFunction'; 219 | } 220 | 221 | // isGenerator 222 | function isGenerator(gtor) { 223 | if (!gtor) return false; 224 | var ctor = gtor.constructor; 225 | return ctor === GeneratorFunctionPrototype || 226 | (ctor.displayName || ctor.name) === 'GeneratorFunctionPrototype' || 227 | typeof gtor.next === 'function'; 228 | } 229 | 230 | 231 | // Channel(empty) 232 | // recv: chan(cb) 233 | // send: chan(err, data) 234 | // send: chan() or chan(undefined) 235 | // send: chan(data) 236 | // chan.end() 237 | // chan.empty 238 | // chan.done() 239 | // chan.send(val or err) 240 | // chan.recv(cb) 241 | 242 | if (setProto) 243 | setProto(Channel.prototype, Function.prototype); 244 | else { 245 | Channel.prototype = Function(); 246 | Channel.prototype.constructor = Channel; 247 | } 248 | 249 | 250 | // Channel(empty) 251 | function Channel(empty) { 252 | if (arguments.length > 1) 253 | throw new Error('Channel: too many arguments'); 254 | 255 | channel.$isClosed = false; // send stream is closed 256 | channel.$isDone = false; // receive stream is done 257 | channel.$recvCallbacks = []; // receive pending callbacks queue 258 | channel.$sendValues = []; // send pending values 259 | 260 | channel.empty = typeof empty === 'function' ? new empty() : empty; 261 | 262 | if (setProto) 263 | setProto(channel, Channel.prototype); 264 | else { 265 | channel.close = $$close; 266 | channel.done = $$done; 267 | channel.send = $$send; 268 | channel.recv = $$recv; 269 | 270 | // for stream 271 | channel.end = $$close; 272 | channel.stream = $$stream; 273 | 274 | if (channel.call !== Function.prototype.call) 275 | channel.call = Function.prototype.call; 276 | 277 | if (channel.apply !== Function.prototype.apply) 278 | channel.apply = Function.prototype.apply; 279 | } 280 | 281 | return channel; 282 | 283 | function channel(a, b) { 284 | // yield callback 285 | if (typeof a === 'function') 286 | return channel.recv(a); 287 | 288 | // error 289 | if (a instanceof Error) 290 | return channel.send(a); 291 | 292 | // value or undefined 293 | if (arguments.length <= 1) 294 | return channel.send(a); 295 | 296 | var args = slice.call(arguments); 297 | 298 | if (a == null) { 299 | if (arguments.length === 2) 300 | return channel.send(b); 301 | else 302 | args.shift(); 303 | } 304 | 305 | // (null, value,...) -> [value, ...] 306 | return channel.send(args); 307 | } 308 | 309 | } // Channel 310 | 311 | // send(val or err) 312 | var $$send = Channel.prototype.send = send; 313 | function send(val) { 314 | if (this.$isClosed) 315 | throw new Error('Cannot send to closed channel'); 316 | else if (this.$recvCallbacks.length > 0) 317 | complete(this.$recvCallbacks.shift(), val); 318 | else 319 | this.$sendValues.push(val); 320 | } // send 321 | 322 | // recv(cb) 323 | var $$recv = Channel.prototype.recv = recv; 324 | function recv(cb) { 325 | if (this.done()) 326 | cb(null, this.empty); 327 | else if (this.$sendValues.length > 0) 328 | complete(cb, this.$sendValues.shift()); 329 | else 330 | this.$recvCallbacks.push(cb); 331 | return; 332 | } // recv 333 | 334 | // done() 335 | var $$done = Channel.prototype.done = done; 336 | function done() { 337 | if (!this.$isDone && this.$isClosed && this.$sendValues.length === 0) { 338 | this.$isDone = true; 339 | // complete each pending callback with the empty value 340 | var empty = this.empty; 341 | this.$recvCallbacks.forEach(function(cb) { complete(cb, empty); }); 342 | } 343 | 344 | return this.$isDone; 345 | } // done 346 | 347 | // close() end() 348 | var $$close = Channel.prototype.close = Channel.prototype.end = close; 349 | function close() { 350 | this.$isClosed = true; 351 | return this.done(); 352 | } // close 353 | 354 | // stream(reader) 355 | var $$stream = Channel.prototype.stream = stream; 356 | function stream(reader) { 357 | var channel = this; 358 | reader.on('end', close); 359 | reader.on('error', error); 360 | reader.on('readable', readable); 361 | return this; 362 | 363 | function close() { return channel.close(); } 364 | function error(err) { try { channel.send(err); } catch (e) {} } 365 | 366 | function readable() { 367 | var buf = this.read(); 368 | if (!buf) return; 369 | try { channel.send(buf); } catch (e) {} 370 | } // readable 371 | } // stream 372 | 373 | // complete(cb, val or err) 374 | function complete(cb, val) { 375 | if (val instanceof Error) 376 | cb(val); 377 | else 378 | cb(null, val); 379 | } // complete 380 | 381 | 382 | function wait(ms) { 383 | return function (cb) { 384 | setTimeout(cb, ms); 385 | }; 386 | }; 387 | 388 | 389 | if (typeof module === 'object' && module && module.exports) 390 | module.exports = aa; 391 | 392 | if (GeneratorFunction) 393 | aa.GeneratorFunction = GeneratorFunction; 394 | 395 | aa.isGeneratorFunction = isGeneratorFunction; 396 | aa.isGenerator = isGenerator; 397 | aa.aa = aa; 398 | aa.chan = aa.Channel = Channel; 399 | aa.wait = wait; 400 | 401 | if (Object.getOwnPropertyNames) 402 | Object.getOwnPropertyNames(PromiseThunk).forEach(function (prop) { 403 | if (!aa.hasOwnProperty(prop)) 404 | setValue(aa, prop, PromiseThunk[prop]); 405 | }); 406 | else 407 | for (var prop in PromiseThunk) 408 | if (!aa.hasOwnProperty(prop)) 409 | setValue(aa, prop, PromiseThunk[prop]); 410 | 411 | return aa; 412 | 413 | }(this.PromiseThunk || require('promise-thunk')); 414 | -------------------------------------------------------------------------------- /aa02.js: -------------------------------------------------------------------------------- 1 | // Callbacks vs Coroutines 2 | // A look ad callbacks vs generators vs coroutines 3 | // https://medium.com/@tjholowaychuk/callbacks-vs-coroutines-174f1fe66127 4 | 5 | // co@3 : thunk version 6 | // co@4 : Promise version 7 | 8 | void function () { 9 | 'use strict'; 10 | 11 | var Promise = require('promise-thunk'); 12 | var isPromise = Promise.isPromise; 13 | var isIterator = Promise.isIterator; 14 | var isIterable = Promise.isIterable; 15 | var makeArrayFromIterator = Promise.makeArrayFromIterator; 16 | 17 | var slice = [].slice; 18 | var push = [].push; 19 | 20 | // Object_getOwnPropertyNames 21 | var Object_getOwnPropertyNames = Object.getOwnPropertyNames || Object.keys || 22 | function (obj) { 23 | var keys = []; 24 | for (var prop in obj) 25 | if (obj.hasOwnProperty(prop)) keys.push(prop); 26 | return keys; 27 | }; 28 | 29 | 30 | // defProp 31 | var defProp = function () { 32 | var obj = {}; 33 | if (!Object.defineProperty) return null; 34 | try { 35 | Object.defineProperty(obj, 'prop', {value: 'str'}); 36 | return obj.prop === 'str' ? Object.defineProperty : null; 37 | } catch (err) { return null; } 38 | } (); 39 | 40 | // setConst(obj, prop, val) 41 | var setConst = defProp ? 42 | function setConst(obj, prop, val) { 43 | defProp(obj, prop, {value: val}); } : 44 | function setConst(obj, prop, val) { obj[prop] = val; }; 45 | 46 | // setValue(obj, prop, val) 47 | var setValue = defProp ? 48 | function setValue(obj, prop, val) { 49 | defProp(obj, prop, {value: val, 50 | writable: true, configurable: true}); } : 51 | function setValue(obj, prop, val) { obj[prop] = val; }; 52 | 53 | // setProto(obj, proto) 54 | var setProto = Object.setPrototypeOf || {}.__proto__ ? 55 | function setProto(obj, proto) { obj.__proto__ = proto; } : null; 56 | 57 | 58 | // GeneratorFunction 59 | try { 60 | var GeneratorFunction = Function('return function*(){}.constructor')(); 61 | GeneratorFunction.toString(); 62 | setValue(aa, 'GeneratorFunction', GeneratorFunction); 63 | } catch (e) {} 64 | 65 | // GeneratorFunctionPrototype 66 | try { 67 | var GeneratorFunctionPrototype = Function('return (function*(){})().constructor')(); 68 | GeneratorFunctionPrototype.toString(); 69 | setValue(aa, 'GeneratorFunctionPrototype', GeneratorFunctionPrototype); 70 | } catch (e) {} 71 | 72 | // isGeneratorFunction 73 | setValue(aa, 'isGeneratorFunction', isGeneratorFunction); 74 | function isGeneratorFunction(gtor) { 75 | if (!gtor) return false; 76 | var ctor = gtor.constructor; 77 | return ctor === GeneratorFunction || 78 | (ctor.displayName || ctor.name) === 'GeneratorFunction'; 79 | } 80 | 81 | // isGenerator 82 | setValue(aa, 'isGenerator', isGenerator); 83 | function isGenerator(gtor) { 84 | if (!gtor) return false; 85 | var ctor = gtor.constructor; 86 | return ctor === GeneratorFunctionPrototype || 87 | (ctor.displayName || ctor.name) === 'GeneratorFunctionPrototype' || 88 | typeof gtor.next === 'function'; 89 | } 90 | 91 | 92 | // nextTickDo(fn, args,...) 93 | var nextTickDo = typeof process === 'object' && process ? process.nextTick : 94 | typeof setImmediate === 'function' ? setImmediate : 95 | function (cb) { 96 | var args = [cb, 0].concat(slice.call(arguments, 1)); 97 | setTimeout.apply(null, args); 98 | }; 99 | 100 | // nextTick(fn, args,...) 101 | var nextTick = function () { 102 | var NEXT_MAX = 50; 103 | var count = 0; 104 | var progress = false; 105 | var head = undefined; 106 | var tail = undefined; 107 | 108 | function nextTick(/* cb, err, val,... */) { 109 | if (head) 110 | return tail = tail.next_next = arguments; 111 | head = tail = arguments; 112 | if (progress) return; 113 | progress = true; 114 | ++count >= NEXT_MAX ? (count = 0, nextTickDo(nextTask)) : nextTask(); 115 | } 116 | 117 | var argscbs = [ 118 | function (args) { return undefined; }, 119 | function (args) { return args[0](); }, 120 | function (args) { return args[0](args[1]); }, 121 | function (args) { return args[0](args[1], args[2]); }, 122 | function (args) { return args[0](args[1], args[2], args[3]); }, 123 | function (args) { return args[0](args[1], args[2], args[3], args[4]); } 124 | ]; 125 | 126 | function nextTask() { 127 | while (head) { 128 | var args = head; 129 | if (head === tail) 130 | head = tail = undefined; 131 | else 132 | head = head.next_next; 133 | argscbs[args.length](args); 134 | } 135 | progress = false; 136 | } 137 | 138 | return nextTick; 139 | }(); 140 | 141 | if (GeneratorFunction) 142 | GeneratorFunction.prototype.aa$callback = function (cb) { gtorcb(this(), cb); }; 143 | Function.prototype.aa$callback = function (cb) { nextTick(this, normalcb(cb)); }; 144 | 145 | function valcb(val, cb) { nextTick(cb, null, val); } 146 | function errcb(err, cb) { nextTick(cb, err); } 147 | function funcb(fun, cb) { fun.aa$callback(cb); } 148 | //function anycb(val, cb) { typecbs[typeof val](val, cb); } 149 | function anycb(val, cb) { val && typeof val.then === 'function' ? promisecb(val, cb) : typecbs[typeof val](val, cb); } 150 | function clscb(val, cb) { val ? ctorcb(val.constructor.displayName || val.constructor.name || '$', val, cb) : nextTick(cb, null, val); } 151 | function ctorcb(name, val, cb) { (ctorcbs[name] ? ctorcbs[name] : ctorcbs.$)(val, cb); } 152 | function promisecb(promise, cb) { promise.then(function (val) { cb(null, val); }, cb); } 153 | 154 | // typecbs[typeof val](val, cb) for any type of value 155 | var typecbs = { 156 | 'function': funcb, 157 | object: clscb, 158 | number: valcb, 159 | string: valcb, 160 | boolean: valcb, 161 | symbol: valcb, 162 | xml: valcb, 163 | undefined: valcb 164 | }; 165 | 166 | // ctorcbs(val, cb) by constructor.name 167 | var ctorcbs = { 168 | Object: function (val, cb) { 169 | typeof val.next === 'function' && typeof val['throw'] === 'function' ? gtorcb(val, cb) : 170 | typeof val.then === 'function' ? promisecb(val, cb) : 171 | val.constructor === Object ? objcb(val, cb) : 172 | valcb(val, cb); }, 173 | Array: parcb, 174 | Error: valcb, 175 | Promise: promisecb, 176 | $: function (val, cb) { 177 | typeof val.next === 'function' && typeof val['throw'] === 'function' ? gtorcb(val, cb) : 178 | typeof val.then === 'function' ? promisecb(val, cb) : 179 | //val instanceof Error ? nextTick(cb, val) : 180 | val.constructor === Array ? parcb(val, cb) : 181 | val.constructor === Object ? objcb(val, cb) : 182 | valcb(val, cb); } 183 | }; 184 | 185 | // parcb(args, cb) for Array 186 | function parcb(args, cb) { 187 | var n = args.length, result = Array(n); 188 | if (n === 0) return nextTick(cb, null, result); 189 | args.forEach(function (arg, i) { 190 | anycb(arg, function (err, val) { 191 | if (err) { 192 | if (n > 0) n = 0, cb(err); 193 | } 194 | else { 195 | result[i] = val; 196 | --n || nextTick(cb, null, result); 197 | } 198 | }); 199 | }); 200 | } 201 | 202 | // objcb(args, cb) for Object 203 | function objcb(args, cb) { 204 | var keys = Object_getOwnPropertyNames(args); 205 | var n = keys.length, result = {}; 206 | if (n === 0) return nextTick(cb, null, result); 207 | keys.forEach(function (key) { 208 | result[key] = undefined; 209 | anycb(args[key], function (err, val) { 210 | if (err) { 211 | if (n > 0) n = 0, cb(err); 212 | } 213 | else { 214 | result[key] = val; 215 | --n || nextTick(cb, null, result); 216 | } 217 | }); 218 | }); 219 | } 220 | 221 | // seqcb(args, cb) for sequential tasks 222 | function seqcb(args, cb) { 223 | var n = args.length, result = Array(n); 224 | if (n === 0) return nextTick(cb, null, result); 225 | anycb(args[0], function (err, val) { chk(val, 0); }); 226 | function chk(x, i) { 227 | result[i] = x; 228 | if (++i < n) nextTick(anycb, args[i], function (err, val) { chk(val, i); }); 229 | else cb(null, result); 230 | } 231 | } 232 | 233 | /* 234 | // co3 235 | function co3(gtor) { 236 | return function (callback) { 237 | nextTickDo(cb); 238 | function cb(err, val) { 239 | try { 240 | val = err ? gtor['throw'](err) : gtor.next(val); 241 | anycb(val.value, val.done ? callback : cb); 242 | } catch (err) { callback(err); } 243 | } 244 | }; 245 | } 246 | 247 | // co4 248 | function co4(gtor) { 249 | return new Promise(function (resolve, reject) { 250 | nextTickDo(cb); 251 | function callback(err, val) { err ? reject(err) : resolve(val); } 252 | function cb(err, val) { 253 | try { 254 | val = err ? gtor['throw'](err) : gtor.next(val); 255 | anycb(val.value, val.done ? callback : cb); 256 | } catch (err) { reject(err); } 257 | } 258 | }); 259 | } 260 | */ 261 | 262 | var slices0 = [ 263 | function (args) { return undefined; }, 264 | function (args) { return args[0]; }, 265 | function (args) { return [args[0], args[1]]; }, 266 | function (args) { return [args[0], args[1], args[2]]; }, 267 | function (args) { return [args[0], args[1], args[2], args[3]]; }, 268 | function (args) { return [args[0], args[1], args[2], args[3], args[4]]; } 269 | ]; 270 | var slices1 = [ 271 | function (args) { return undefined; }, 272 | function (args) { return undefined; }, 273 | function (args) { return args[1]; }, 274 | function (args) { return [args[1], args[2]]; }, 275 | function (args) { return [args[1], args[2], args[3]]; }, 276 | function (args) { return [args[1], args[2], args[3], args[4]]; } 277 | ]; 278 | //var slice0 = function (args, len) { return len <= 5 ? slices0[len](args) : slice.call(args); }; 279 | //var slice1 = function (args, len) { return len <= 5 ? slices1[len](args) : slice.call(args, 1); }; 280 | 281 | function normalcb(cb) { 282 | return function callback(err, val) { 283 | if (err != null) 284 | if (err instanceof Error) cb.apply(this, arguments); 285 | else cb.call(this, null, slices0[arguments.length](arguments)); 286 | else cb.call(this, null, slices1[arguments.length](arguments)); 287 | return callback; 288 | }; 289 | } // normalcb 290 | 291 | function gtorcb(gtor, callback) { 292 | nextTick(cb); 293 | function cb(err, val) { 294 | try { 295 | if (err) { 296 | if (typeof gtor['throw'] !== 'function') 297 | return callback(err); 298 | val = gtor['throw'](err); 299 | } 300 | else { 301 | if (typeof val === 'function') 302 | return val.aa$callback(cb); //funcb(val, cb); 303 | if (typeof val === 'object' && val) { 304 | if (typeof val.then === 'function') 305 | return promisecb(val, cb); 306 | if (typeof val.next === 'function' && 307 | typeof val['throw'] === 'function') 308 | return gtorcb(val, cb); 309 | } 310 | val = gtor.next(val); 311 | } 312 | anycb(val.value, val.done ? callback : cb); 313 | } catch (err) { callback(err); } 314 | } 315 | } // gtorcb 316 | 317 | // aa - async-await 318 | function aa(val) { 319 | if (arguments.length === 0) return Channel(); 320 | if (arguments.length <= 1 && typeof val === 'function' && !isGeneratorFunction(val)) return aa.promisify(val); 321 | var resolve, reject, callback, result; 322 | var promise = new Promise(function (res, rej) { resolve = res; reject = rej; }); 323 | if (arguments.length <= 1) 324 | nextTickDo(anycb, val, cb); 325 | else 326 | nextTickDo(seqcb, arguments, cb); 327 | return promise; 328 | //thunk.then = promise.then.bind(promise); 329 | //thunk['catch'] = promise['catch'].bind(promise); 330 | //return thunk; 331 | 332 | //function thunk(cb) { 333 | // callback = cb; 334 | // try { result && callback.apply(null, result); } 335 | // catch (err) { reject(err); } 336 | //} 337 | function cb(err, val) { 338 | err ? reject(err) : resolve(val); 339 | result = arguments; 340 | try { callback && callback.apply(null, result); } 341 | catch (err) { reject(err); } 342 | } 343 | } // aa 344 | 345 | 346 | // Channel() 347 | // recv: chan(cb) 348 | // send: chan(err, val) 349 | // send: chan() or chan(undefined) 350 | // send: chan(val) 351 | // chan.end() 352 | // chan.done() 353 | // chan.stream(reader) 354 | 355 | // aa.Channel() 356 | setValue(aa, 'Channel', Channel); 357 | setValue(aa, 'chan', Channel); 358 | 359 | // Channel 360 | function Channel() { 361 | var values = [], callbacks = slice.call(arguments); 362 | var isClosed = false, isDone = false; 363 | var chan = normalcb(channel); 364 | 365 | chan.stream = stream; 366 | function stream(reader) { 367 | reader.on('end', end); 368 | reader.on('error', chan); 369 | reader.on('readable', readable); 370 | return chan; 371 | function readable() { 372 | var buf = reader.read(); 373 | if (!buf) return; 374 | chan(null, buf); 375 | } // readable 376 | } // stream 377 | 378 | chan.end = chan.close = end; 379 | function end() { 380 | isClosed = true; 381 | return done(); 382 | } // end 383 | 384 | chan.done = done; 385 | function done() { 386 | if (!isDone && isClosed && !values.length) { 387 | isDone = true; 388 | // complete each pending callback with the undefined value 389 | while (callbacks.length) 390 | try { callbacks.shift().call(chan); } 391 | catch (err) { values.unshift([err]); } 392 | } 393 | return isDone; 394 | } // done 395 | 396 | return chan; 397 | 398 | function channel(err, val) { 399 | if (typeof val === 'function') 400 | callbacks.push(val); 401 | else if (val && typeof val[0] === 'function') 402 | push.apply(callbacks, val); 403 | else if (val && typeof val.then === 'function') 404 | return val.then(chan, chan), chan; 405 | else if (isClosed) 406 | throw new Error('Cannot send to closed channel'); 407 | else 408 | values.push(arguments); 409 | while (callbacks.length) { 410 | while (callbacks.length && values.length) 411 | try { callbacks.shift().apply(chan, values.shift()); } 412 | catch (err) { values.unshift([err]); } 413 | if (isClosed && callbacks.length) 414 | try { callbacks.shift().call(chan); } 415 | catch (err) { values.unshift([err]); } 416 | else break; 417 | } 418 | return chan; 419 | } // channel 420 | } // Channel 421 | 422 | 423 | // aa.wait(msec, val) 424 | setValue(aa, 'wait', wait); 425 | function wait(msec, val) { 426 | return function (cb) { 427 | setTimeout(cb, msec, null, val); 428 | }; 429 | } 430 | 431 | 432 | // aa.callback(gtor) 433 | setValue(aa, 'callback', callback); 434 | function callback(gtor) { 435 | return function () { 436 | return aa(gtor.apply(this, arguments)); 437 | }; 438 | } 439 | 440 | 441 | setValue(aa, 'Promise', Promise); 442 | setValue(aa, 'PromiseThunk', Promise); 443 | 444 | if (Object.getOwnPropertyNames) 445 | Object.getOwnPropertyNames(PromiseThunk).forEach(function (prop) { 446 | if (!aa.hasOwnProperty(prop)) 447 | setValue(aa, prop, PromiseThunk[prop]); 448 | }); 449 | else 450 | for (var prop in PromiseThunk) 451 | if (!aa.hasOwnProperty(prop)) 452 | setValue(aa, prop, PromiseThunk[prop]); 453 | 454 | setValue(aa, 'aa', aa); 455 | if (typeof module === 'object' && module && module.exports) 456 | module.exports = aa; 457 | }(); 458 | -------------------------------------------------------------------------------- /draft/aa-diff.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | let aas = ['aa', 'aa01', 'aa02'].map( 6 | mod => ({name: mod, object: require('../' + mod)}) 7 | ); 8 | 9 | let keys = Object.keys(aas.reduce((z, x) => { 10 | Object.getOwnPropertyNames(x.object).forEach(p => { 11 | //if (typeof x.object[p] === 'function') 12 | z[p] = ''; 13 | }); 14 | return z; 15 | }, {})).sort(); 16 | 17 | let aa = aas[0].object; 18 | 19 | aas.forEach(x => { 20 | console.log('\n'); 21 | let s = ''; 22 | keys.forEach(p => { 23 | //if (typeof x.object[p] !== 'function') return; 24 | s += (x.object[p] + '').split('\n').map(s => p + ': ' + s) 25 | .join('\n') + '\n'; 26 | let pd = Object.getOwnPropertyDescriptor(x.object, p) || {}; 27 | console.log(x.name, 28 | (pd.writable ? 'W' : 'w') + 29 | (pd.enumerable ? 'E' : 'e') + 30 | (pd.configurable ? 'C' : 'c'), 31 | typeof pd.value === 'function' ? 32 | (pd.value + '') === (aa[p] + '') ? '==' : '!=' 33 | : ' ', 34 | typeof pd.value === 'number' || 35 | typeof pd.value === 'string' ? pd.value : ' ', 36 | typeof pd.value, 37 | p); 38 | //console.log(p, aa[p]); 39 | }); 40 | fs.writeFileSync('zzz-' + x.name + '-contents.log', s); 41 | console.log('\n'); 42 | }); 43 | -------------------------------------------------------------------------------- /draft/aa02-test1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const aa = require('../aa'); 4 | const aa02 = require('../aa02'); 5 | const util = require('util'); 6 | 7 | // sleep(ms, args,... cb) : node style normal callback 8 | function sleep(ms) { 9 | var args = [].slice.call(arguments, 1), cb = args.pop(); 10 | if (ms >= 0) 11 | setTimeout.apply(null, [cb, ms, null].concat(args)); 12 | else 13 | setTimeout(cb, 0, new RangeError('sleep ms must be plus')); 14 | } 15 | 16 | 17 | // delay(ms, args,...)(cb) : thunk 18 | function delay(ms) { 19 | var args = [].slice.call(arguments); 20 | return function delayThunk(cb) { 21 | sleep.apply(null, args.concat(cb)); 22 | }; 23 | } 24 | 25 | 26 | // aa(fn) | aa.wrap(fn) : returns wrapped function a.k.a thunkify and promisefy 27 | // wait(ms, args,...) : returns promise & thunk 28 | var wait = aa.promisify(sleep); 29 | 30 | function *main(chan) { 31 | console.log(util.inspect( 32 | yield wait(20, 4), 33 | {colors:true, depth:null})); 34 | console.log(util.inspect( 35 | yield delay(20, 4), 36 | {colors:true, depth:null})); 37 | 38 | // yield [] -> like Promise.all([]) ! 39 | console.log(util.inspect( 40 | yield [wait(20, 4), wait(30, 5), wait(10, 6)], 41 | {colors:true, depth:null})); 42 | 43 | console.log(util.inspect( 44 | yield [delay(20, 4), delay(30, 5), delay(10, 6)], 45 | {colors:true, depth:null})); 46 | 47 | console.log(util.inspect( 48 | yield {x:wait(20, 4), y:wait(30, 5), z:wait(10, 6)}, 49 | {colors:true, depth:null})); 50 | 51 | console.log(util.inspect( 52 | yield {x:delay(20, 4), y:delay(30, 5), z:delay(10, 6)}, 53 | {colors:true, depth:null})); 54 | 55 | console.log(yield wait(20, 4)((err, val) => wait(30, 5))((err, val) => wait(10, 6))); 56 | 57 | const ch = chan(); 58 | setTimeout(ch, 200, 'ok2'); 59 | setTimeout(ch, 100, 'ok1'); 60 | console.log('ch start'); 61 | console.log('ch wait', yield ch, yield ch); 62 | setTimeout(ch, 200, 'ok2'); 63 | setTimeout(ch, 100, 'ok1'); 64 | console.log('ch wait', yield [ch, ch]); 65 | } 66 | 67 | aa(main(aa.chan)) 68 | .then(() => console.log('----')) 69 | .then(() => aa02(main(aa.chan))); 70 | -------------------------------------------------------------------------------- /draft/promise-diff.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | let promises = ['promise-light', 'promise-thunk'].map( 6 | mod => ({name: mod, object: require(mod)}) 7 | ); 8 | promises.push({name: 'promise', object: Promise}) 9 | let p0 = promises[0].object; 10 | 11 | let keys = Object.keys(promises.reduce((z, x) => { 12 | Object.getOwnPropertyNames(x.object).forEach(p => { 13 | //if (typeof x.object[p] === 'function') 14 | z[p] = ''; 15 | }); 16 | return z; 17 | }, {})).sort(); 18 | 19 | promises.forEach(x => { 20 | console.log('\n'); 21 | let s = ''; 22 | keys.forEach(p => { 23 | //if (typeof x.object[p] !== 'function') return; 24 | s += (x.object[p] + '').split('\n').map(s => p + ': ' + s) 25 | .join('\n') + '\n'; 26 | let pd = Object.getOwnPropertyDescriptor(x.object, p) || {}; 27 | console.log(x.name, 28 | (pd.writable ? 'W' : 'w') + 29 | (pd.enumerable ? 'E' : 'e') + 30 | (pd.configurable ? 'C' : 'c'), 31 | typeof pd.value === 'function' ? 32 | (pd.value + '') === (p0[p] + '') ? '==' : '!=' 33 | : ' ', 34 | typeof pd.value === 'number' || 35 | typeof pd.value === 'string' ? pd.value : ' ', 36 | typeof pd.value, 37 | p); 38 | }); 39 | fs.writeFileSync('zzz-' + x.name + '-contents.log', s); 40 | console.log('\n'); 41 | }); 42 | -------------------------------------------------------------------------------- /draft/thunkify-new.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var slice = Array.prototype.slice; 4 | 5 | // function thunkify 6 | function thunkify(fn) { 7 | return function () { 8 | var callback, results, called; 9 | // var args = slice.call(arguments); 10 | // args.push(function () { 11 | // results = arguments; 12 | // done(); 13 | // }); 14 | // arguments.__proto__ = Array.prototype; 15 | arguments[arguments.length++] = function () { 16 | results = arguments; 17 | done(); 18 | }; 19 | fn.apply(null, arguments); 20 | return function (fn) { 21 | callback = fn; 22 | done(); 23 | }; 24 | function done() { 25 | if (!callback || !results || called) return; 26 | called = true; 27 | callback.apply(null, results); 28 | } 29 | }; 30 | } // function thunkify 31 | 32 | exports = module.exports = thunkify; 33 | -------------------------------------------------------------------------------- /draft/thunkify-old.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var slice = Array.prototype.slice; 4 | 5 | // function thunkify 6 | function thunkify(fn) { 7 | return function () { 8 | var callback, results, called; 9 | var args = slice.call(arguments); 10 | args.push(function () { 11 | results = arguments; 12 | done(); 13 | }); 14 | // arguments[arguments.length++] = function () { 15 | // results = arguments; 16 | // done(); 17 | // }; 18 | fn.apply(null, args); // arguments); 19 | return function (fn) { 20 | callback = fn; 21 | done(); 22 | }; 23 | function done() { 24 | if (!callback || !results || called) return; 25 | called = true; 26 | callback.apply(null, results); 27 | } 28 | }; 29 | } // function thunkify 30 | 31 | exports = module.exports = thunkify; 32 | -------------------------------------------------------------------------------- /draft/thunkify-test.cmd: -------------------------------------------------------------------------------- 1 | node thunkify 2 | node thunkify-new 3 | node thunkify-old 4 | node thunkify-test 5 | node thunkify-timer-test 6 | @pause 7 | -------------------------------------------------------------------------------- /draft/thunkify-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var thunkify = require('./thunkify'); 4 | 5 | var fs = require('fs'); 6 | var aa = require('../aa'); 7 | 8 | var timer = thunkify(function (ms, cb) { 9 | return setTimeout(cb, ms); 10 | }); 11 | 12 | var tm = function (){ 13 | return new Date().toISOString() + ' '; 14 | } 15 | 16 | var read = thunkify(fs.readFile); 17 | 18 | aa(function*(){ 19 | yield aa(function*(){ 20 | console.log(tm() + 'timer1'); 21 | yield timer(300); 22 | console.log(tm() + 'timer2'); 23 | yield timer(300); 24 | console.log(tm() + 'timer3'); 25 | }); 26 | 27 | yield aa(function*(){ 28 | console.log(tm() + 't11'); 29 | var t = timer(300); 30 | setTimeout(function (){ 31 | console.log(tm() + 't12'); 32 | t(function(){ 33 | console.log(tm() + 't13'); 34 | }); 35 | }, 500); 36 | }); 37 | 38 | yield aa(function*(){ 39 | console.log(tm() + 't21'); 40 | var t = timer(300); 41 | setTimeout(function (){ 42 | console.log(tm() + 't22'); 43 | t(function(){ 44 | console.log(tm() + 't23'); 45 | }); 46 | }, 200); 47 | }); 48 | 49 | })(); 50 | -------------------------------------------------------------------------------- /draft/thunkify-timer-test.js: -------------------------------------------------------------------------------- 1 | // test 2 | 3 | 'use strict'; 4 | 5 | var thunkify = require('./thunkify'); 6 | 7 | var fs = require('fs'); 8 | var aa = require('../aa'); 9 | 10 | //var timer = thunkify(function (ms, cb) { 11 | // return setTimeout(cb, ms); 12 | //}); 13 | 14 | var timer = function (ms) { 15 | setTimeout(cb1, ms); 16 | var callback, results, called; 17 | function cb1() { 18 | results = arguments; 19 | if (!callback || called) return; 20 | called = true; 21 | callback.apply(this, results); 22 | } 23 | return function (cb) { 24 | callback = cb; 25 | if (!results || called) return; 26 | called = true; 27 | callback.apply(this, results); 28 | } 29 | } 30 | 31 | var tm = function (){ 32 | return new Date().toISOString() + ' '; 33 | } 34 | 35 | var read = thunkify(fs.readFile); 36 | 37 | aa(function*(){ 38 | yield aa(function*(){ 39 | console.log(tm() + 'timer1'); 40 | yield timer(300); 41 | console.log(tm() + 'timer2'); 42 | yield timer(300); 43 | console.log(tm() + 'timer3'); 44 | }); 45 | 46 | yield aa(function*(){ 47 | console.log(tm() + 't11'); 48 | var t = timer(300); 49 | setTimeout(function (){ 50 | console.log(tm() + 't12'); 51 | t(function(){ 52 | console.log(tm() + 't13'); 53 | }); 54 | }, 500); 55 | }); 56 | 57 | yield aa(function*(){ 58 | console.log(tm() + 't21'); 59 | var t = timer(300); 60 | setTimeout(function (){ 61 | console.log(tm() + 't22'); 62 | t(function(){ 63 | console.log(tm() + 't23'); 64 | }); 65 | }, 200); 66 | }); 67 | 68 | })(); 69 | -------------------------------------------------------------------------------- /draft/thunkify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function thunkify(fn) { 4 | return function () { 5 | var callback, results, called, context; 6 | arguments[arguments.length++] = function () { 7 | results = arguments; 8 | context = this; 9 | if (!callback || called) return; 10 | called = true; 11 | callback.apply(context, results); 12 | }; 13 | 14 | fn.apply(this, arguments); 15 | 16 | return function (fn) { 17 | callback = fn; 18 | if (!results || called) return; 19 | called = true; 20 | callback.apply(context, results); 21 | }; 22 | }; 23 | } 24 | 25 | exports = module.exports = thunkify; 26 | -------------------------------------------------------------------------------- /examples/aa-ex.js: -------------------------------------------------------------------------------- 1 | // aa-ex.js 2 | 3 | (function main() { 4 | 5 | var aa = require('../aa'); 6 | var PromiseThunk = require('promise-thunk'); 7 | var TIME = 300; 8 | var LONG_TIME = 500; 9 | 10 | // thunk 11 | function sleep1(ms) { 12 | return function (cb) { 13 | if (ms < 0) cb(new RangeError('msec must be plus number')); 14 | else setTimeout(function () { cb(); }, ms); 15 | }; 16 | } 17 | 18 | // native Promise 19 | function sleep2(ms) { 20 | return new Promise(function (res, rej) { 21 | if (ms < 0) rej(new RangeError('msec must be plus number')); 22 | else setTimeout(res, ms); 23 | }); 24 | } 25 | 26 | // PromiseThunk 27 | function sleep3(ms) { 28 | return PromiseThunk(function (res, rej) { 29 | if (ms < 0) rej(new RangeError('msec must be plus number')); 30 | else setTimeout(res, ms); 31 | }); 32 | } 33 | 34 | function makeLast(msg) { 35 | return function (err, val) { 36 | if (err) 37 | console.log(msg, ': \x1b[41merr:', err + '\x1b[m'); 38 | else 39 | console.log(msg, ': \x1b[42mval:', val + '\x1b[m'); 40 | }; 41 | } 42 | 43 | aa(function *aaMain() { 44 | 45 | console.log(); 46 | console.log('*** yield 10, 20, and return 30'); 47 | yield aa(function *(){ yield 10; yield 20; return 30; }) 48 | (makeLast(' gf')); 49 | 50 | console.log(); 51 | console.log('*** yield 11, 22, and return 33'); 52 | yield aa(function *(){ yield 11; yield 22; return 33; }()) 53 | (makeLast(' gt')); 54 | 55 | console.log(); 56 | console.log('*** yield 52, 51, and return 50'); 57 | yield aa({i: 53, next: function (){ return {value: --this.i, done: this.i <= 50}; }}) 58 | (makeLast(' {}')); 59 | 60 | console.log(); 61 | console.log('*** sleep thunk version'); 62 | yield aa(function *() { 63 | console.log('111x'); 64 | yield sleep1(TIME); 65 | console.log('222x'); 66 | yield sleep1(TIME); 67 | console.log('333x'); 68 | try { 69 | yield sleep1(-1); 70 | } catch (e) { makeLast('888x')(e); } 71 | console.log('444x'); 72 | yield sleep1(-1); 73 | console.log('555x'); 74 | return '999x'; 75 | }) 76 | (makeLast(' x')); 77 | 78 | console.log(); 79 | console.log('*** sleep native Promise version'); 80 | yield aa(function *() { 81 | console.log('111p'); 82 | yield sleep2(TIME); 83 | console.log('222p'); 84 | yield sleep2(TIME); 85 | console.log('333p'); 86 | try { 87 | yield sleep2(-1); 88 | } catch (e) { makeLast('888p')(e); } 89 | console.log('444p'); 90 | yield sleep2(-1); 91 | console.log('555p'); 92 | return '999p'; 93 | }) 94 | (makeLast(' p')); 95 | 96 | console.log(); 97 | console.log('*** sleep PromiseThunk version'); 98 | yield aa(function *() { 99 | console.log('111z'); 100 | yield sleep3(TIME); 101 | console.log('222z'); 102 | yield sleep3(TIME); 103 | console.log('333z'); 104 | try { 105 | yield sleep3(-1); 106 | } catch (e) { makeLast('888z')(e); } 107 | console.log('444z'); 108 | yield sleep3(-1); 109 | console.log('555z'); 110 | return '999z'; 111 | }) 112 | (makeLast(' z')); 113 | 114 | console.log(); 115 | console.log('*** conext object this and arguments'); 116 | yield aa.call({x:1,y:2}, function *(a, b, c) { 117 | console.log('', this, [].slice.call(arguments)); 118 | }, 11, 22, 33) 119 | (function (e, v) { console.log('xxx'); return sleep1(LONG_TIME); }) 120 | (function (e, v) { console.log('xxx'); return sleep2(LONG_TIME); }) 121 | (function (e, v) { console.log('xxx'); return sleep3(LONG_TIME); }); 122 | 123 | console.log(); 124 | console.log('*** conext object this and arguments'); 125 | yield aa.call({x:1,y:2}, function *(a, b, c) { 126 | console.log('', this, [].slice.call(arguments)); 127 | }, 11, 22, 33) 128 | (function (e, v) { console.log('xxx'); return sleep1(LONG_TIME); }) 129 | (function (e, v) { console.log('xxx'); return sleep2(LONG_TIME); }) 130 | (function (e, v) { console.log('xxx'); return sleep3(LONG_TIME); }); 131 | 132 | }); 133 | 134 | })(); 135 | -------------------------------------------------------------------------------- /examples/aa-generator-ex.js: -------------------------------------------------------------------------------- 1 | // aa-generator-ex.js 2 | 3 | (function () { 4 | 5 | var aa = require('../aa'); 6 | //var aa = require('co'); 7 | 8 | var slice = [].slice; 9 | 10 | var startTime = Date.now(); 11 | var counter = 0; 12 | var fired = true; 13 | var timer = setInterval(function () { fired = true; }, 1000); 14 | 15 | // pr(msgs...) 16 | function pr() { 17 | if (fired) { 18 | console.log(counter + '\t' + slice.call(arguments).join(' ')); 19 | fired = false; 20 | } 21 | } 22 | 23 | // delay thunk 24 | function delay(ms, val) { 25 | return function (cb) { 26 | ++counter; 27 | function callback() { 28 | cb(null, val); 29 | } 30 | if (ms <= 0) setImmediate(callback); 31 | else setTimeout(callback, ms); 32 | }; 33 | } 34 | 35 | var ms = 0; 36 | var depth = 18; 37 | 38 | // gen1 generator 39 | function * gen1(indent, indentString) { 40 | if (!indent) indent = 0; 41 | pr(yield delay(ms, indentString + indent + ': a')); 42 | if (indent < depth) yield * gen1(indent + 1, indentString + ' '); 43 | pr(yield delay(ms, indentString + indent + ': b')); 44 | if (indent < depth) yield gen1(indent + 1, indentString + ' '); 45 | pr(yield delay(ms, indentString + indent + ': c')); 46 | return indentString + indent + ': ret'; 47 | } 48 | 49 | aa(function * () { 50 | pr('000: init'); 51 | pr(yield delay(ms, '111: start')); 52 | pr(yield gen1(0, ' ')); 53 | pr(yield delay(ms, '999: end')); 54 | pr('ZZZ:', counter); 55 | clearInterval(timer); 56 | console.log(counter + '\ttime: ' + (Date.now() - startTime) / 1000.0 + ' sec'); 57 | return counter; 58 | }).then( 59 | function (val) { console.log(counter + '\tval: ' + val); }, 60 | function (err) { console.log(counter + '\terr: ' + err); }); 61 | 62 | })(); 63 | -------------------------------------------------------------------------------- /examples/aa-generator-function-ex.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var aa = require('../aa'); 3 | //var aa = require('co'); 4 | 5 | function *genFunc2() { 6 | console.log(yield [111]); 7 | console.log(yield [222]); 8 | console.log(yield [333]); 9 | console.log(999); 10 | return 999; 11 | } 12 | 13 | function *genFunc() { 14 | console.log(yield [11]); 15 | var val = yield genFunc2; 16 | if (val !== 999) throw new Error('unexpected 999 !== ' + val); 17 | console.log('xxx', val); 18 | console.log(yield [22]); 19 | val = yield genFunc2(); 20 | if (val !== 999) throw new Error('unexpected 999 !== ' + val); 21 | console.log('yyy', val); 22 | console.log(yield [33]); 23 | console.log(99); 24 | return 99; 25 | } 26 | 27 | function makeCb(msg) { 28 | return function (val) { console.log(msg + ' ' + val); }; 29 | } 30 | 31 | aa(genFunc ).then(makeCb('xx val'), makeCb('xx err')); 32 | aa(genFunc()).then(makeCb('yy val'), makeCb('yy err')); 33 | 34 | })(); 35 | -------------------------------------------------------------------------------- /examples/aa-readme-ex01-seq.js: -------------------------------------------------------------------------------- 1 | try { 2 | var aa = require('../aa'); 3 | } catch (e) { 4 | var aa = require('aa'); 5 | } 6 | 7 | 8 | aa(main); 9 | 10 | 11 | function *main() { 12 | console.log('11:', yield asyncPromise(100, 11)); 13 | console.log('12:', yield asyncThunk(100, 12)); 14 | console.log('13:', yield asyncGenerator(100, 13)); 15 | yield sub(20); 16 | yield sub(30); 17 | } 18 | 19 | 20 | function *sub(base) { 21 | console.log('%s: %s', base + 1, yield asyncPromise(100, base + 1)); 22 | console.log('%s: %s', base + 2, yield asyncThunk(100, base + 2)); 23 | console.log('%s: %s', base + 3, yield asyncGenerator(100, base + 3)); 24 | } 25 | 26 | 27 | // asyncPromise(msec, arg) : promise 28 | function asyncPromise(msec, arg) { 29 | return new Promise(function (resolve, reject) { 30 | setTimeout(resolve, msec, arg); 31 | }); 32 | } 33 | 34 | 35 | // asyncThunk(msec, arg) : thunk 36 | function asyncThunk(msec, arg) { 37 | return function (callback) { 38 | setTimeout(callback, msec, null, arg); 39 | }; 40 | } 41 | 42 | 43 | // asyncGenerator(msec, arg) : generator 44 | function *asyncGenerator(msec, arg) { 45 | var chan = aa.Channel(); 46 | setTimeout(chan, msec, arg); 47 | return yield chan; 48 | } 49 | -------------------------------------------------------------------------------- /examples/aa-readme-ex02-par.js: -------------------------------------------------------------------------------- 1 | try { 2 | var aa = require('../aa'); 3 | } catch (e) { 4 | var aa = require('aa'); 5 | } 6 | 7 | 8 | aa(main); 9 | 10 | 11 | function *main() { 12 | console.log('[11, 12, 13]:', yield [ 13 | asyncPromise(100, 11), 14 | asyncThunk(100, 12), 15 | asyncGenerator(100, 13) 16 | ]); 17 | 18 | console.log('{x:11, y:12, z:13}:', yield { 19 | x: asyncPromise(100, 11), 20 | y: asyncThunk(100, 12), 21 | z: asyncGenerator(100, 13) 22 | }); 23 | 24 | yield [sub(20), sub(30)]; 25 | } 26 | 27 | 28 | function *sub(base) { 29 | console.log('%s: %s', base + 1, yield asyncPromise(100, base + 1)); 30 | console.log('%s: %s', base + 2, yield asyncThunk(100, base + 2)); 31 | console.log('%s: %s', base + 3, yield asyncGenerator(100, base + 3)); 32 | } 33 | 34 | 35 | // asyncPromise(msec, arg) : promise 36 | function asyncPromise(msec, arg) { 37 | return new Promise(function (resolve, reject) { 38 | setTimeout(resolve, msec, arg); 39 | }); 40 | } 41 | 42 | 43 | // asyncThunk(msec, arg) : thunk 44 | function asyncThunk(msec, arg) { 45 | return function (callback) { 46 | setTimeout(callback, msec, null, arg); 47 | }; 48 | } 49 | 50 | 51 | // asyncGenerator(msec, arg) : generator 52 | function *asyncGenerator(msec, arg) { 53 | var chan = aa.Channel(); 54 | setTimeout(chan, msec, arg); 55 | return yield chan; 56 | } 57 | -------------------------------------------------------------------------------- /examples/aa-readme-ex11-promisify.js: -------------------------------------------------------------------------------- 1 | try { 2 | var aa = require('../aa'); 3 | } catch (e) { 4 | var aa = require('aa'); 5 | } 6 | 7 | 8 | var promisify = aa.promisify; 9 | var asyncPromise = promisify(asyncCallback); 10 | 11 | 12 | aa(main); 13 | 14 | 15 | function *main() { 16 | console.log('11:', yield asyncPromise(100, 11)); 17 | console.log('12:', yield asyncPromise(100, 12)); 18 | console.log('13:', yield asyncPromise(100, 13)); 19 | 20 | asyncPromise(100, 21) 21 | .then(function (val) { 22 | console.log('21:', val); 23 | return asyncPromise(100, 22); 24 | }) 25 | .then(function (val) { 26 | console.log('22:', val); 27 | return asyncPromise(100, 23); 28 | }) 29 | .then(function (val) { 30 | console.log('23:', val); 31 | }); 32 | } 33 | 34 | 35 | // asyncCallback(msec, arg. callback) : node style normal callback 36 | // callback : function (err, val) 37 | function asyncCallback(msec, arg, callback) { 38 | setTimeout(callback, msec, null, arg); 39 | } 40 | -------------------------------------------------------------------------------- /examples/aa-readme-ex12-thunkify.js: -------------------------------------------------------------------------------- 1 | try { 2 | var aa = require('../aa'); 3 | } catch (e) { 4 | var aa = require('aa'); 5 | } 6 | 7 | 8 | var thunkify = aa.thunkify; 9 | var asyncThunk = thunkify(asyncCallback); 10 | 11 | 12 | aa(main); 13 | 14 | 15 | function *main() { 16 | console.log('11:', yield asyncThunk(100, 11)); 17 | console.log('12:', yield asyncThunk(100, 12)); 18 | console.log('13:', yield asyncThunk(100, 13)); 19 | 20 | asyncThunk(100, 21) 21 | (function (err, val) { 22 | console.log('21:', val); 23 | asyncThunk(100, 22) 24 | (function (err, val) { 25 | console.log('22:', val); 26 | asyncThunk(100, 23) 27 | (function (err, val) { 28 | console.log('23:', val); 29 | }); 30 | }); 31 | }); 32 | } 33 | 34 | 35 | // asyncCallback(msec, arg. callback) : node style normal callback 36 | // callback : function (err, val) 37 | function asyncCallback(msec, arg, callback) { 38 | setTimeout(callback, msec, null, arg); 39 | } 40 | -------------------------------------------------------------------------------- /examples/aa-readme-example.js: -------------------------------------------------------------------------------- 1 | try { 2 | var aa = require('../aa'); 3 | } catch (e) { 4 | var aa = require('aa'); 5 | } 6 | 7 | 8 | // sleep(msec, args,... callback) : node style normal callback 9 | // callback : function (err, val) 10 | function sleep(msec) { 11 | var args = [].slice.call(arguments, 1); 12 | setTimeout.apply(null, [args.pop(), msec, null].concat(args)); 13 | } 14 | 15 | sleep(1000, function (err, val) { console.log('1000 msec OK'); }); 16 | 17 | 18 | // delay(msec, args,...)(callback) : thunk 19 | // callback : function (err, val) 20 | function delay(msec) { 21 | var args = [].slice.call(arguments); 22 | return function (callback) { 23 | sleep.apply(null, args.concat(callback)); 24 | }; 25 | } 26 | // var delay = aa.thunkify(sleep); 27 | 28 | delay(1100)( 29 | function (err, val) { console.log('1100 msec OK'); } 30 | ); 31 | 32 | 33 | // aa.promisify(fn) : returns wrapped function a.k.a thunkify and promisify 34 | // wait(msec, args,...) : returns promise & thunk 35 | var wait = aa.promisify(sleep); 36 | 37 | // wait() : as a thunk 38 | wait(1200)( 39 | function (err, val) { console.log('1200 msec OK'); } 40 | ); 41 | 42 | // wait() : as a promise 43 | wait(1300).then( 44 | function (val) { console.log('1300 msec OK'); }, 45 | function (err) { console.log('1300 msec NG', err); } 46 | ).catch( 47 | function (err) { console.log('1300 msec NG2', err); } 48 | ); 49 | 50 | 51 | // aa(generator) : returns promise & thunk 52 | aa(function *() { 53 | 54 | yield 1; // primitive value 55 | yield [1, 2, 3]; // array 56 | yield {x:1, y:2, z:3}; // object 57 | 58 | 59 | // wait for promise 60 | yield Promise.resolve(2); 61 | 62 | 63 | // wait for thunk 64 | yield delay(800); 65 | 66 | 67 | // wait for promise or thunk 68 | yield wait(800); 69 | 70 | 71 | console.log('0:', yield wait(300, 0)); 72 | console.log('1:', yield wait(300, 1)); 73 | 74 | 75 | // yield Promise.all([]) 76 | console.log('[1, 2, 3]:', 77 | yield Promise.all([wait(200, 1), wait(300, 2), wait(100, 3)])); 78 | 79 | 80 | // yield [] -> like Promise.all([]) ! 81 | console.log('[4, 5, 6]:', 82 | yield [wait(200, 4), wait(300, 5), wait(100, 6)]); 83 | 84 | 85 | // yield {} -> like Promise.all({}) !? 86 | console.log('{x:7, y:8, z:9}:', 87 | yield {x:wait(200, 7), y:wait(300, 8), z:wait(100, 9)}); 88 | 89 | 90 | // make channel for sync - fork and join 91 | var chan = aa.Channel(); 92 | 93 | sleep(300, 20, chan); // send value to channel : fork or spread 94 | sleep(200, 10, chan); // send value to channel : fork or spread 95 | var a = yield chan; // recv value from channel : join or sync 96 | var b = yield chan; // recv value from channel : join or sync 97 | console.log('10 20:', a, b); 98 | 99 | 100 | // fork thread - make new thread and start 101 | aa(function *() { 102 | yield wait(200); // wait 200 msec 103 | return 200; 104 | })(chan); // send 200 to channel : join or sync 105 | 106 | // fork thread - make new thread and start 107 | aa(function *() { 108 | yield wait(100); // wait 100 msec 109 | return 100; 110 | })(chan); // send 100 to channel : join or sync 111 | 112 | // fork thread - make new thread and start 113 | aa(function *() { 114 | yield wait(300); // wait 300 115 | return 300; 116 | })(chan); // send 300 to channel : join or sync 117 | 118 | // join threads - sync threads 119 | var x = yield chan; // wait & recv first value from channel 120 | var y = yield chan; // wait & recv second value from channel 121 | var z = yield chan; // wait & recv third value from channel 122 | console.log('top 3 winners: 100 200 300:', x, y, z); 123 | 124 | 125 | // communicate with channels 126 | var chan1 = aa.Channel(), chan2 = aa.Channel(); 127 | 128 | // thread 1: send to chan1, recv from chan2 129 | aa(function *() { 130 | sleep(100, 111, chan1); 131 | console.log('222:', yield chan2); 132 | sleep(100, 333, chan1); 133 | console.log('444:', yield chan2); 134 | sleep(100, 555, chan1); 135 | return 666; 136 | })(chan); 137 | 138 | // thread 1: recv from chan1, send to chan2 139 | aa(function *() { 140 | console.log('111:', yield chan1); 141 | sleep(100, 222, chan2); 142 | console.log('333:', yield chan1); 143 | sleep(100, 444, chan2); 144 | console.log('555:', yield chan1); 145 | return 777; 146 | })(chan); 147 | console.log('666 777:', yield chan, yield chan); 148 | 149 | return 11; 150 | }) 151 | .then( 152 | function (val) { 153 | console.log('11 val:', val); 154 | return wait(100, 22); }, 155 | function (err) { 156 | console.log('11 err:', err); 157 | return wait(100, 22); } 158 | ) 159 | (function (err, val) { 160 | console.log('22 val:', val, err ? 'err:' + err : ''); 161 | return wait(100, 33); }) 162 | (function (err, val) { 163 | console.log('33 val:', val, err ? 'err:' + err : ''); 164 | return wait(100, 44); }) 165 | .then( 166 | function (val) { 167 | console.log('44 val:', val); 168 | return wait(100, 55); }, 169 | function (err) { 170 | console.log('44 err:', err); 171 | return wait(100, 55); } 172 | ) 173 | .catch( 174 | function (err) { 175 | console.log('55 err:', err); 176 | return wait(100, 66); } 177 | ); 178 | -------------------------------------------------------------------------------- /examples/aa-test.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var util = require('util'), inspect = util.inspect; 5 | function ins(x) { 6 | return inspect(x, {colors: true}); 7 | } 8 | 9 | try { var aa = require('../aa'); } 10 | catch (err) { var aa = require('aa'); } 11 | 12 | function coSleep(ms, val) { 13 | return function (fn) { 14 | setTimeout(function () { 15 | if (val < 3) fn(null, val); 16 | else fn(new Error('sleep error')); 17 | }, ms); 18 | }; 19 | } 20 | 21 | function promiseSleep(ms, val) { 22 | return new Promise(function (resolve, reject) { 23 | setTimeout(function () { 24 | if (val < 3) resolve(val); 25 | else reject(new Error('sleep error')); 26 | }, ms); 27 | }); 28 | } 29 | 30 | function clog(msg) { 31 | var args = [].slice.call(arguments, 1); 32 | console.log('\x1b[36m' + msg + '\x1b[m ' + args.map(ins).join(' ')); 33 | } 34 | 35 | var p = aa.call('this', function *() { 36 | var args = [].slice.call(arguments); 37 | clog('gfn this:', this); 38 | clog('gfn args:', args); 39 | try { 40 | clog('coSleep(200, 1):', yield coSleep(200, 1)); 41 | clog('coSleep(200, 2):', yield coSleep(200, 2)); 42 | clog('coSleep(200, 3):', yield coSleep(200, 3)); 43 | } catch (err) { 44 | clog('coSleep err?', err + ''); 45 | console.log('\x1b[31m' + err.stack + '\x1b[m'); 46 | } 47 | try { 48 | clog('promiseSleep(200, 1):', yield promiseSleep(200, 1)); 49 | clog('promiseSleep(200, 2):', yield promiseSleep(200, 2)); 50 | clog('promiseSleep(200, 3):', yield promiseSleep(200, 3)); 51 | } catch (err) { 52 | clog('promiseSleep err?', err + ''); 53 | console.log('\x1b[31m' + err.stack + '\x1b[m'); 54 | } 55 | clog('[th,th]:', yield [coSleep(200, 1), coSleep(200, 2)]); 56 | clog('[pr,pr]:', yield [promiseSleep(200, 1), promiseSleep(200, 2)]); 57 | clog('[[pr,co,3]]:', yield [[promiseSleep(200, 1), coSleep(200, 2), 3]]); 58 | 59 | clog('{x:th,y:th}:', yield {x:coSleep(200, 1), y:coSleep(200, 2)}); 60 | clog('{x:pr,y:pr}:', yield {x:promiseSleep(200, 1), y:promiseSleep(200, 2)}); 61 | clog('{w:{x:pr,y:co,z:3}}:', yield {w:{x:promiseSleep(200, 1), y:coSleep(200, 2), z:3}}); 62 | 63 | throw new Error('gfn error'); 64 | //return 'gfn last'; 65 | }, 'args0'); 66 | 67 | if (typeof p === 'function') 68 | p(function (err, val) { clog('thunk final:', err, val); }); 69 | else if (p && typeof p.then === 'function') 70 | p.then(function (val) { clog('promise final ok:', val); }, 71 | function (err) { clog('promise final ng:', err); }); 72 | else 73 | console.log(p); 74 | 75 | })(); 76 | -------------------------------------------------------------------------------- /examples/aa02-http-server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const aa = require('../aa'); 5 | const aa02 = require('../aa02'); 6 | let reqId = 1000; 7 | 8 | http.createServer(aa.callback(function *(req, res) { 9 | const id = ++reqId; 10 | let count = 0; 11 | console.log(id, ++count, 'aa', new Date, req.method, req.url, req.httpVersion); 12 | yield aa.wait(3000); 13 | console.log(id, ++count, 'aa', new Date, req.method, req.url, req.httpVersion); 14 | res.end(`hello ${req.method} ${req.url} ${req.httpVersion}`); 15 | })).listen(process.env.PORT || 3000); 16 | 17 | http.createServer(aa02.callback(function *(req, res) { 18 | const id = ++reqId; 19 | let count = 0; 20 | console.log(id, ++count, 'aa02', new Date, req.method, req.url, req.httpVersion); 21 | yield aa.wait(3000); 22 | console.log(id, ++count, 'aa02', new Date, req.method, req.url, req.httpVersion); 23 | res.end(`hello ${req.method} ${req.url} ${req.httpVersion}`); 24 | })).listen(3001); 25 | -------------------------------------------------------------------------------- /examples/aa2.js: -------------------------------------------------------------------------------- 1 | // aa.js - async-await.js 2 | 3 | this.aa = function () { 4 | var PromiseThunk = require('promise-thunk'); 5 | var PromiseLight = require('promise-light'); 6 | var isPromise = PromiseThunk.isPromise; 7 | var wrap = PromiseThunk.wrap; 8 | 9 | // GeneratorFunction 10 | try { 11 | var GeneratorFunction = Function('return function*(){}.constructor')(); 12 | } catch (e) {} 13 | 14 | // GeneratorFunctionPrototype 15 | try { 16 | var GeneratorFunctionPrototype = Function('return (function*(){})().constructor')(); 17 | } catch (e) {} 18 | 19 | var slice = [].slice; 20 | 21 | // defProp 22 | var defProp = function (obj) { 23 | if (!Object.defineProperty) return null; 24 | try { 25 | Object.defineProperty(obj, 'prop', {value: 'str'}); 26 | return obj.prop === 'str' ? Object.defineProperty : null; 27 | } catch (err) { return null; } 28 | } ({}); 29 | 30 | // setConst(obj, prop, val) 31 | var setConst = defProp ? 32 | function setConst(obj, prop, val) { 33 | defProp(obj, prop, {value: val}); } : 34 | function setConst(obj, prop, val) { obj[prop] = val; }; 35 | 36 | // setValue(obj, prop, val) 37 | var setValue = defProp ? 38 | function setValue(obj, prop, val) { 39 | defProp(obj, prop, {value: val, 40 | writable: true, configurable: true}); } : 41 | function setValue(obj, prop, val) { obj[prop] = val; }; 42 | 43 | // setProto(obj, proto) 44 | var setProto = Object.setPrototypeOf || {}.__proto__ ? 45 | function setProto(obj, proto) { obj.__proto__ = proto; } : null; 46 | 47 | 48 | // nextTickDo(fn) 49 | var nextTickDo = typeof setImmediate === 'function' ? setImmediate : 50 | typeof process === 'object' && process && typeof process.nextTick === 'function' ? process.nextTick : 51 | function nextTick(fn) { setTimeout(fn, 0); }; 52 | 53 | var tasks = []; 54 | var nextTickProgress = false; 55 | 56 | // nextTick(fn, ...args) 57 | function nextTick(fn) { 58 | if (typeof fn !== 'function') 59 | throw new TypeError('fn must be a function'); 60 | 61 | tasks.push(arguments); 62 | if (nextTickProgress) return; 63 | 64 | nextTickProgress = true; 65 | nextTickDo(function () { 66 | var args; 67 | while (args = tasks.shift()) 68 | args[0](args[1], args[2]); 69 | nextTickProgress = false; 70 | }); 71 | } 72 | 73 | 74 | // aa - async-await 75 | function aa(gtor) { 76 | var ctx = this, args = slice.call(arguments, 1); 77 | 78 | // is generator function? then get generator. 79 | if (gtor instanceof GeneratorFunction) 80 | gtor = gtor.apply(ctx, args); 81 | 82 | // is promise? then do it. 83 | if (isPromise(gtor)) 84 | return PromiseThunk(gtor); 85 | 86 | // is function? then wrap it. 87 | if (typeof gtor === 'function') 88 | return wrap.call(ctx, gtor); 89 | 90 | // is not generator? 91 | if (!isGenerator(gtor)) 92 | return Channel.apply(ctx, arguments); 93 | 94 | var resolve, reject, p = new PromiseLight( // PtomiseThunk( 95 | function (res, rej) { resolve = res; reject = rej; }); 96 | 97 | nextTick(callback); 98 | return p; 99 | 100 | function callback(err, val) { 101 | try { 102 | if (err) { 103 | if (typeof gtor['throw'] !== 'function') 104 | return reject(err); 105 | var ret = gtor['throw'](err); 106 | } 107 | else 108 | var ret = gtor.next(val); 109 | } catch (err) { 110 | return reject(err); 111 | } 112 | 113 | if (ret.done) 114 | return resolve(ret.value); 115 | 116 | nextTick(doValue, ret.value, callback); 117 | } 118 | 119 | function doValue(value, callback) { 120 | //if (value == null || 121 | // typeof value !== 'object' && 122 | // typeof value !== 'function') 123 | // return callback(null, value); 124 | 125 | if (value == null) 126 | return callback(null, value); 127 | 128 | //if (value instanceof GeneratorFunction) 129 | if (value.constructor === GeneratorFunction) 130 | value = value.apply(ctx, args); 131 | 132 | var ctor = value.constructor; 133 | 134 | // function must be a thunk 135 | if (typeof value === 'function') 136 | return value(callback); 137 | 138 | else if (typeof value === 'object') { 139 | //if (value instanceof GeneratorFunctionPrototype || isGenerator(value)) 140 | //if (value instanceof GeneratorFunctionPrototype || value.next) 141 | //if (value.constructor === GeneratorFunctionPrototype || value.next) 142 | if (value.next) 143 | //return aa.call(ctx, value)(callback); 144 | return aa.call(ctx, value).then(function (val) { callback(null, val); }, callback); 145 | 146 | //if (isPromise(value)) 147 | if (value.then) 148 | return value.then(function (val) { callback(null, val); }, callback); 149 | } 150 | else 151 | return callback(null, value); 152 | 153 | var called = false; 154 | 155 | // array 156 | //if (value instanceof Array) { 157 | if (ctor === Array) { 158 | var n = value.length; 159 | if (n === 0) return callback(null, []); 160 | var arr = Array(n); 161 | value.forEach(function (val, i) { 162 | doValue(val, function (err, val) { 163 | if (err) { 164 | if (!called) 165 | called = true, callback(err); 166 | } 167 | else { 168 | arr[i] = val; 169 | if (--n === 0 && !called) 170 | called = true, callback(null, arr); 171 | } 172 | }); 173 | }); 174 | } // array 175 | 176 | // object 177 | else if (ctor === Object) { 178 | var keys = Object.keys(value); 179 | var n = keys.length; 180 | if (n === 0) return callback(null, {}); 181 | var obj = {}; 182 | keys.forEach(function (key) { 183 | obj[key] = undefined; 184 | doValue(value[key], function (err, val) { 185 | if (err) { 186 | if (!called) 187 | called = true, callback(err); 188 | } 189 | else { 190 | obj[key] = val; 191 | if (--n === 0 && !called) 192 | called = true, callback(null, obj); 193 | } 194 | }); 195 | }); 196 | } // object 197 | 198 | // other value 199 | else 200 | return callback(null, value); 201 | } 202 | } 203 | 204 | 205 | // isGeneratorFunction 206 | function isGeneratorFunction(gtor) { 207 | return gtor instanceof GeneratorFunction; 208 | } 209 | 210 | // isGenerator 211 | function isGenerator(gtor) { 212 | return gtor instanceof GeneratorFunctionPrototype || !!gtor && gtor.next === 'function'; 213 | } 214 | 215 | 216 | // Channel(empty) 217 | // recv: chan(cb) 218 | // send: chan(err, data) 219 | // send: chan() or chan(undefined) 220 | // send: chan(data) 221 | // chan.end() 222 | // chan.empty 223 | // chan.done() 224 | // chan.send(val or err) 225 | // chan.recv(cb) 226 | 227 | if (setProto) 228 | setProto(Channel.prototype, Function.prototype); 229 | else { 230 | Channel.prototype = Function(); 231 | Channel.prototype.constructor = Channel; 232 | } 233 | 234 | 235 | // Channel(empty) 236 | function Channel(empty) { 237 | if (arguments.length > 1) 238 | throw new Error('Channel: too many arguments'); 239 | 240 | channel.$isClosed = false; // send stream is closed 241 | channel.$isDone = false; // receive stream is done 242 | channel.$recvCallbacks = []; // receive pending callbacks queue 243 | channel.$sendValues = []; // send pending values 244 | 245 | channel.empty = typeof empty === 'function' ? new empty() : empty; 246 | 247 | if (setProto) 248 | setProto(channel, Channel.prototype); 249 | else { 250 | channel.close = $$close; 251 | channel.done = $$done; 252 | channel.send = $$send; 253 | channel.recv = $$recv; 254 | 255 | // for stream 256 | channel.end = $$close; 257 | channel.stream = $$stream; 258 | 259 | if (channel.call !== Function.prototype.call) 260 | channel.call = Function.prototype.call; 261 | 262 | if (channel.apply !== Function.prototype.apply) 263 | channel.apply = Function.prototype.apply; 264 | } 265 | 266 | return channel; 267 | 268 | function channel(a, b) { 269 | // yield callback 270 | if (typeof a === 'function') 271 | return channel.recv(a); 272 | 273 | // error 274 | if (a instanceof Error) 275 | return channel.send(a); 276 | 277 | // value or undefined 278 | if (arguments.length <= 1) 279 | return channel.send(a); 280 | 281 | var args = slice.call(arguments); 282 | 283 | if (a == null) { 284 | if (arguments.length === 2) 285 | return channel.send(b); 286 | else 287 | args.shift(); 288 | } 289 | 290 | // (null, value,...) -> [value, ...] 291 | return channel.send(args); 292 | } 293 | 294 | } // Channel 295 | 296 | // send(val or err) 297 | var $$send = Channel.prototype.send = send; 298 | function send(val) { 299 | if (this.$isClosed) 300 | throw new Error('Cannot send to closed channel'); 301 | else if (this.$recvCallbacks.length > 0) 302 | complete(this.$recvCallbacks.shift(), val); 303 | else 304 | this.$sendValues.push(val); 305 | } // send 306 | 307 | // recv(cb) 308 | var $$recv = Channel.prototype.recv = recv; 309 | function recv(cb) { 310 | if (this.done()) 311 | cb(null, this.empty); 312 | else if (this.$sendValues.length > 0) 313 | complete(cb, this.$sendValues.shift()); 314 | else 315 | this.$recvCallbacks.push(cb); 316 | return; 317 | } // recv 318 | 319 | // done() 320 | var $$done = Channel.prototype.done = done; 321 | function done() { 322 | if (!this.$isDone && this.$isClosed && this.$sendValues.length === 0) { 323 | this.$isDone = true; 324 | // complete each pending callback with the empty value 325 | var empty = this.empty; 326 | this.$recvCallbacks.forEach(function(cb) { complete(cb, empty); }); 327 | } 328 | 329 | return this.$isDone; 330 | } // done 331 | 332 | // close() end() 333 | var $$close = Channel.prototype.close = Channel.prototype.end = close; 334 | function close() { 335 | this.$isClosed = true; 336 | return this.done(); 337 | } // close 338 | 339 | // stream(reader) 340 | var $$stream = Channel.prototype.stream = stream; 341 | function stream(reader) { 342 | var channel = this; 343 | reader.on('end', close); 344 | reader.on('error', error); 345 | reader.on('readable', readable); 346 | return this; 347 | 348 | function close() { return channel.close(); } 349 | function error(err) { return channel.send(err); } 350 | 351 | function readable() { 352 | var buf = this.read(); 353 | if (!buf) return; 354 | channel.send(buf); 355 | } // readable 356 | } // stream 357 | 358 | // complete(cb, val or err) 359 | function complete(cb, val) { 360 | if (val instanceof Error) 361 | cb(val); 362 | else 363 | cb(null, val); 364 | } // complete 365 | 366 | 367 | function wait(ms) { 368 | return function (cb) { 369 | setTimeout(cb, ms); 370 | }; 371 | }; 372 | 373 | 374 | if (typeof module === 'object' && module && module.exports) 375 | module.exports = aa; 376 | 377 | if (GeneratorFunction) 378 | aa.GeneratorFunction = GeneratorFunction; 379 | 380 | aa.isGeneratorFunction = isGeneratorFunction; 381 | aa.isGenerator = isGenerator; 382 | aa.aa = aa; 383 | aa.chan = aa.Channel = Channel; 384 | aa.wait = wait; 385 | 386 | if (Object.getOwnPropertyNames) 387 | Object.getOwnPropertyNames(PromiseThunk).forEach(function (prop) { 388 | if (!aa.hasOwnProperty(prop)) 389 | setValue(aa, prop, PromiseThunk[prop]); 390 | }); 391 | else 392 | for (var prop in PromiseThunk) 393 | if (!aa.hasOwnProperty(prop)) 394 | setValue(aa, prop, PromiseThunk[prop]); 395 | 396 | return aa; 397 | 398 | }(); 399 | -------------------------------------------------------------------------------- /examples/my-inspect.js: -------------------------------------------------------------------------------- 1 | this.inspect = function () { 2 | 'use strict'; 3 | 4 | var INDENT = ' '; 5 | 6 | //***************************************************** 7 | function inspect(obj, level, indent) { 8 | if (!level) level = 0, indent = ''; 9 | switch (typeof obj) { 10 | case 'object': 11 | if (obj === null) return 'null'; 12 | var indent2 = indent + INDENT; 13 | level++; 14 | if (obj instanceof Array) { 15 | if (obj.length === 0) return '[]'; 16 | var str = '[\n' + indent; 17 | for (var i = 0, n = obj.length; i < n; ++i) 18 | str += INDENT + inspect(obj[i], level, indent2) + (i < n - 1 ? ',' + '\n' + indent : ''); 19 | return str + ']'; 20 | } 21 | else { 22 | var str = '{\n' + indent, i = 0, n = Object.keys(obj).length; 23 | if (n === 0) return '{}'; 24 | for (var p in obj) 25 | str += INDENT + p + ': ' + inspect(obj[p], level, indent2) + (++i < n ? ',' + '\n' + indent : ''); 26 | return str + ' }'; 27 | } 28 | case 'number': 29 | case 'string': 30 | case 'boolean': 31 | case 'null': // ES6? 32 | case 'undefined': 33 | return obj + ''; 34 | case 'function': return 'function'; 35 | default: 36 | throw new TypeError(typeof obj); 37 | } 38 | } 39 | 40 | return inspect; 41 | }(); 42 | -------------------------------------------------------------------------------- /examples/thunkify-work-main.js: -------------------------------------------------------------------------------- 1 | // test 2 | 3 | 'use strict'; 4 | 5 | var thunkify = require('../aa').thunkify; 6 | 7 | var fs = require('fs'); 8 | var aa = require('../aa'); 9 | 10 | var timer = thunkify(function (ms, cb) { 11 | return setTimeout(cb, ms); 12 | }); 13 | 14 | var tm = function (){ 15 | return new Date().toISOString() + ' '; 16 | } 17 | 18 | var read = thunkify(fs.readFile); 19 | 20 | aa(function*(){ 21 | yield aa(function*(){ 22 | console.log(tm() + 'timer1'); 23 | yield timer(300); 24 | console.log(tm() + 'timer2'); 25 | yield timer(300); 26 | console.log(tm() + 'timer3'); 27 | }); 28 | 29 | yield aa(function*(){ 30 | console.log(tm() + 't11'); 31 | var t = timer(300); 32 | setTimeout(function (){ 33 | console.log(tm() + 't12'); 34 | t(function(){ 35 | console.log(tm() + 't13'); 36 | }); 37 | }, 500); 38 | }); 39 | 40 | yield aa(function*(){ 41 | console.log(tm() + 't21'); 42 | var t = timer(300); 43 | setTimeout(function (){ 44 | console.log(tm() + 't22'); 45 | t(function(){ 46 | console.log(tm() + 't23'); 47 | }); 48 | }, 200); 49 | }); 50 | 51 | })(); 52 | -------------------------------------------------------------------------------- /examples/thunkify-work-main2.js: -------------------------------------------------------------------------------- 1 | // test 2 | 3 | 'use strict'; 4 | 5 | var thunkify = require('../aa').thunkify; 6 | 7 | var addSync = thunkify(function (a1, a2, cb) { 8 | cb(null, a1 + a2); 9 | cb(null, a2 - a1); 10 | }); 11 | 12 | var addAsync = thunkify(function (a1, a2, cb) { 13 | setTimeout(function () { 14 | cb(null, a1 + a2); 15 | }, 400); 16 | setTimeout(function () { 17 | cb(null, a2 - a1); 18 | }, 500); 19 | }); 20 | 21 | var tm = function (){ 22 | return new Date().toISOString() + ' '; 23 | } 24 | 25 | var thunk1 = addSync(12, 34); 26 | thunk1(function (err, data) { console.log(tm() + 'addSync callback 1! ' + data); }); 27 | thunk1(function (err, data) { console.log(tm() + 'addSync callback 2! ' + data); }); 28 | 29 | var thunk2 = addAsync(12, 34); 30 | setTimeout(thunk2(function (err, data) { console.log(tm() + 'addAsync callback 1! ' + data); }), 300); 31 | setTimeout(thunk2(function (err, data) { console.log(tm() + 'addAsync callback 2! ' + data); }), 600); 32 | 33 | var thunk3 = addAsync(12, 34); 34 | setTimeout(thunk3(function (err, data) { console.log(tm() + 'addAsync callback 3! ' + data); }), 700); 35 | setTimeout(thunk3(function (err, data) { console.log(tm() + 'addAsync callback 4! ' + data); }), 900); 36 | -------------------------------------------------------------------------------- /examples/tree-aa.js: -------------------------------------------------------------------------------- 1 | // tree-sync.js 2 | 3 | this.tree = function () { 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var inspect = require('./my-inspect').inspect; 9 | 10 | var aa = require('../aa'); 11 | //var aa = require('co'); 12 | var fs_stat = aa(fs.stat); 13 | var fs_readdir = aa(fs.readdir); 14 | 15 | var $totalsize = '*totalsize*'; 16 | var $error = '*error*'; 17 | var $path = '*path*'; 18 | 19 | var currentPath = ''; 20 | 21 | //***************************************************** 22 | function *tree(file, minSize, level) { 23 | if (!file) file = '.'; 24 | if (!minSize) minSize = 0; 25 | if (!level) level = 0; 26 | 27 | currentPath = file; 28 | 29 | var children = {}; 30 | try { 31 | var stat = yield fs_stat(file); 32 | if (!stat.isDirectory()) 33 | return stat.size; 34 | 35 | var totalsize = 0; 36 | 37 | var names = yield fs_readdir(file); 38 | var result = yield names.map(function (name) { 39 | return tree(path.resolve(file, name), minSize, level + 1); 40 | }); 41 | 42 | result.forEach(function (child, i) { 43 | var name = names[i]; 44 | 45 | if (typeof child === 'number') { 46 | totalsize += child; 47 | children[name] = child; 48 | } 49 | else { 50 | var size = child[$totalsize]; 51 | if (Number.isFinite(size)) totalsize += size; 52 | children[name + '/'] = size < minSize ? size : child; 53 | } 54 | }); // result.forEach 55 | 56 | children[$path] = file; 57 | children[$totalsize] = totalsize; 58 | return children; 59 | } catch (err) { 60 | children[$path] = file; 61 | children[$error] = err + ''; 62 | return children; 63 | } 64 | } // tree 65 | 66 | 67 | tree.tree = tree; 68 | 69 | // node.js module.exports 70 | if (typeof module === 'object' && module && module.exports) { 71 | module.exports = tree; 72 | 73 | // main 74 | if (require.main === module) { 75 | if (!process.argv[2]) 76 | return console.log('usage: iojs %s {path} [min-size]', 77 | process.argv[1]) 78 | var file = path.resolve(process.argv[2] || '.'); 79 | var minSize = eval(process.argv[3]) || 0; 80 | console.log('tree main:', file); 81 | require('control-c')( 82 | function () { 83 | console.error(currentPath); 84 | console.error('time: %d sec', (Date.now() - startTime) / 1000.0); 85 | }, 86 | function () { process.exit(); }); 87 | var startTime = Date.now(); 88 | aa(function *() { 89 | var val = yield tree(file, minSize, 0); 90 | console.log(inspect(val)); 91 | console.log('time: %d sec', (Date.now() - startTime) / 1000.0); 92 | }); 93 | } 94 | 95 | } 96 | 97 | return tree; 98 | }(); 99 | -------------------------------------------------------------------------------- /examples/tree-async.js: -------------------------------------------------------------------------------- 1 | // tree-async.js 2 | 3 | this.tree = function () { 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var inspect = require('./my-inspect').inspect; 9 | 10 | var $totalsize = '*totalsize*'; 11 | var $error = '*error*'; 12 | var $path = '*path*'; 13 | 14 | var currentPath = ''; 15 | 16 | //***************************************************** 17 | function tree(file, minSize, level, cb) { 18 | if (!file) file = '.'; 19 | if (!minSize) minSize = 0; 20 | if (!level) level = 0; 21 | 22 | currentPath = file; 23 | 24 | if (typeof cb !== 'function') 25 | throw new TypeError('tree callback ' + cb + ' must be a function'); 26 | 27 | cb = function (cb) { 28 | var called; 29 | return function (err, val) { 30 | if (called) return; 31 | called = true; 32 | if (err) cb(null, {'*path*':file, '*error*': err + ''}); 33 | else cb(null, val); 34 | }; 35 | } (cb); 36 | 37 | var stat = fs.stat(file, function (err, stat) { 38 | if (err) 39 | return cb(err); 40 | 41 | if (!stat.isDirectory()) 42 | return cb(null, stat.size); 43 | 44 | var children = {}; 45 | var totalsize = 0; 46 | fs.readdir(file, function (err, names) { 47 | 48 | if (err) return cb(err); 49 | 50 | var n = names.length; 51 | if (n === 0) return last(); 52 | 53 | names.forEach(function (name) { 54 | tree(path.resolve(file, name), minSize, level + 1, function (err, child) { 55 | if (err) return cb(err); 56 | 57 | if (typeof child === 'number') { 58 | totalsize += child; 59 | children[name] = child; 60 | } 61 | else { 62 | var size = child[$totalsize]; 63 | if (Number.isFinite(size)) totalsize += size; 64 | children[name + '/'] = size < minSize ? size : child; 65 | } 66 | if (--n === 0) last(); 67 | 68 | }); // tree 69 | 70 | }); // names.forEach 71 | 72 | function last() { 73 | children[$path] = file; 74 | children[$totalsize] = totalsize; 75 | return cb(null, children); 76 | } 77 | 78 | 79 | }); 80 | 81 | 82 | }); // fs.stat 83 | 84 | } // tree 85 | 86 | 87 | tree.tree = tree; 88 | 89 | // node.js module.exports 90 | if (typeof module === 'object' && module && module.exports) { 91 | module.exports = tree; 92 | 93 | // main 94 | if (require.main === module) { 95 | if (!process.argv[2]) 96 | return console.log('usage: iojs %s {path} [min-size]', 97 | process.argv[1]) 98 | var file = path.resolve(process.argv[2] || '.'); 99 | var minSize = eval(process.argv[3]) || 0; 100 | console.log('tree main:', file); 101 | require('control-c')( 102 | function () { 103 | console.error(currentPath); 104 | console.error('time: %d sec', (Date.now() - startTime) / 1000.0); 105 | }, 106 | function () { process.exit(); }); 107 | var startTime = Date.now(); 108 | var val = tree(file, minSize, 0, function (err, val) { 109 | if (err) console.log(err); 110 | else console.log(inspect(val)); 111 | console.log('time: %d sec', (Date.now() - startTime) / 1000.0); 112 | }); 113 | } 114 | 115 | } 116 | 117 | return tree; 118 | }(); 119 | -------------------------------------------------------------------------------- /examples/tree-sync.js: -------------------------------------------------------------------------------- 1 | // tree-sync.js 2 | 3 | this.tree = function () { 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var inspect = require('./my-inspect').inspect; 9 | 10 | var $totalsize = '*totalsize*'; 11 | var $error = '*error*'; 12 | var $path = '*path*'; 13 | 14 | var counter = 0; 15 | 16 | //***************************************************** 17 | function tree(file, minSize, level) { 18 | if (!file) file = '.'; 19 | if (!minSize) minSize = 0; 20 | if (!level) level = 0; 21 | 22 | var children = {}; 23 | try { 24 | var stat = fs.statSync(file); 25 | if (!stat.isDirectory()) 26 | return stat.size; 27 | 28 | var totalsize = 0; 29 | 30 | var names = fs.readdirSync(file); 31 | names.forEach(function (name) { 32 | var child = tree(path.resolve(file, name), minSize, level + 1); 33 | if (typeof child === 'number') { 34 | totalsize += child; 35 | children[name] = child; 36 | } 37 | else { 38 | var size = child[$totalsize]; 39 | if (Number.isFinite(size)) totalsize += size; 40 | children[name + '/'] = size < minSize ? size : child; 41 | } 42 | }); // names.forEach 43 | 44 | children[$path] = file; 45 | children[$totalsize] = totalsize; 46 | return children; 47 | } catch (err) { 48 | children[$path] = file; 49 | children[$error] = err + ''; 50 | return children; 51 | } 52 | } // tree 53 | 54 | 55 | tree.tree = tree; 56 | 57 | // node.js module.exports 58 | if (typeof module === 'object' && module && module.exports) { 59 | module.exports = tree; 60 | 61 | // main 62 | if (require.main === module) { 63 | if (!process.argv[2]) 64 | return console.log('usage: iojs %s {path} [min-size]', 65 | process.argv[1]) 66 | var file = path.resolve(process.argv[2] || '.'); 67 | var minSize = eval(process.argv[3]) || 0; 68 | console.log('tree main:', file); 69 | var startTime = Date.now(); 70 | var val = tree(file, minSize, 0); 71 | console.log(inspect(val)); 72 | console.log('time: %d sec', (Date.now() - startTime) / 1000.0); 73 | } 74 | 75 | } 76 | 77 | return tree; 78 | }(); 79 | -------------------------------------------------------------------------------- /examples/tree.js: -------------------------------------------------------------------------------- 1 | // tree.js 2 | 3 | this.tree = function () { 4 | 'use strict'; 5 | 6 | //var aa = require('co'); 7 | var aa = require('../aa'); 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | var $totalsize = '*totalsize*'; 11 | var $error = '*error*'; 12 | var $path = '*path*'; 13 | var INDENT = ' '; 14 | 15 | var readdir = thunkify(fs.readdir); 16 | 17 | var counter = 0; 18 | 19 | //***************************************************** 20 | function *tree(dir, minSize, level) { 21 | if (!dir) dir = '.'; 22 | if (!level) level = 0; 23 | 24 | var children = {}; 25 | var totalsize = 0; 26 | 27 | try { 28 | var procName = 'tree: fs.readdir: '; 29 | var names = yield readdir(dir); 30 | 31 | var res = names.map(function (name) { 32 | var file = path.resolve(dir, name); 33 | return {name:name, file:file, stat:fs_stat(file)}; 34 | }); 35 | 36 | // sync parallel: fs.stat 37 | procName = 'tree: fs_stat: '; 38 | res = yield res; 39 | 40 | procName = 'tree: check fs.stat: '; 41 | res.forEach(function (elem) { 42 | elem.size = 0; 43 | elem.child = null; 44 | 45 | if (elem.stat instanceof Error) { 46 | console.log('tree: fs.stat error: ' + elem.stat); 47 | return; 48 | } 49 | 50 | elem.size = elem.stat.size; 51 | 52 | if (elem.stat.isDirectory()) { 53 | elem.name += '/'; 54 | elem.child = tree(elem.file, minSize, level + 1); 55 | } 56 | 57 | children[elem.name] = null; 58 | }); 59 | 60 | // sync parallel: tree 61 | procName = 'tree: tree() '; 62 | res = yield res; 63 | 64 | // rest of process 65 | procName = 'tree: after tree() '; 66 | res.forEach(function (elem) { 67 | var name = elem.name; 68 | var size = elem.size; 69 | var child = elem.child; 70 | 71 | if (child && Number.isFinite(child[$totalsize])) { 72 | if (child[$totalsize] >= minSize) 73 | children[name] = child; 74 | else 75 | children[name] = child[$totalsize]; 76 | totalsize += child[$totalsize]; 77 | } 78 | else 79 | children[name] = size; 80 | 81 | totalsize += size; 82 | }); 83 | 84 | children[$totalsize] = totalsize; 85 | 86 | } catch (err) { 87 | console.log(procName + err); 88 | children[$error] = procName + err; 89 | } 90 | 91 | children[$path] = dir; 92 | return children; 93 | } 94 | 95 | //***************************************************** 96 | // thunkify(fn) 97 | function thunkify(fn) { 98 | return function () { 99 | var args = [].slice.call(arguments); 100 | return function (cb) { 101 | fn.apply(null, args.concat(cb)); 102 | }; 103 | }; 104 | } // thunkify 105 | 106 | //***************************************************** 107 | function fs_stat(file) { 108 | return function (cb) { 109 | fs.stat(file, function (err, stat) { 110 | if (err) cb(null, err); // !!! error -> data !!! 111 | else cb(null, stat); 112 | }); 113 | }; 114 | } // fs_stat 115 | 116 | //***************************************************** 117 | function inspect(obj, level, indent) { 118 | if (!level) level = 0, indent = ''; 119 | switch (typeof obj) { 120 | case 'object': 121 | if (obj === null) return 'null'; 122 | var indent2 = indent + INDENT; 123 | level++; 124 | if (obj instanceof Array) { 125 | if (obj.length === 0) return '[]'; 126 | var str = '[\n' + indent; 127 | for (var i = 0, n = obj.length; i < n; ++i) 128 | str += INDENT + inspect(obj[i], level, indent2) + (i < n - 1 ? ',' + '\n' + indent : ''); 129 | return str + ']'; 130 | } 131 | else { 132 | var str = '{\n' + indent, i = 0, n = Object.keys(obj).length; 133 | if (n === 0) return '{}'; 134 | for (var p in obj) 135 | str += INDENT + p + ': ' + inspect(obj[p], level, indent2) + (++i < n ? ',' + '\n' + indent : ''); 136 | return str + ' }'; 137 | } 138 | case 'number': 139 | case 'string': 140 | case 'boolean': 141 | case 'null': // ES6? 142 | case 'undefined': 143 | return obj + ''; 144 | case 'function': return 'function'; 145 | default: 146 | throw new TypeError(typeof obj); 147 | } 148 | } 149 | 150 | tree.tree = tree; 151 | 152 | // node.js module.exports 153 | if (typeof module === 'object' && module && module.exports) { 154 | module.exports = tree; 155 | 156 | // main 157 | if (require.main === module) { 158 | var dir = path.resolve(process.argv[2] || '.'); 159 | console.log('tree main:', dir); 160 | aa(tree(dir, eval(process.argv[3]) || 0, 0)) 161 | .then( 162 | function (val) { 163 | console.log(inspect(val)); 164 | }, 165 | function (err) { 166 | console.log(err.stack); 167 | } 168 | ); // then 169 | } 170 | 171 | } 172 | 173 | return tree; 174 | }(); 175 | -------------------------------------------------------------------------------- /lib/chan.js: -------------------------------------------------------------------------------- 1 | // chan.js 2 | 3 | (function() { 4 | 'use strict'; 5 | 6 | var slice = Array.prototype.slice; 7 | 8 | // Channel(empty) 9 | // recv: chan(cb) 10 | // send: chan(err, data) 11 | // send: chan() or chan(undefined) 12 | // send: chan(data) 13 | // chan.end() 14 | // chan.readable() 15 | // chan.empty 16 | // chan.done() 17 | // chan.send(val or err) 18 | // chan.recv(cb) 19 | 20 | // setProto(obj, proto) 21 | var setProto = Object.setPrototypeOf || {}.__proto__ ? 22 | function setProto(obj, proto) { obj.__proto__ = proto; } : null; 23 | 24 | if (setProto) 25 | setProto(Channel.prototype, Function.prototype); 26 | else { 27 | Channel.prototype = Function(); 28 | Channel.prototype.constructor = Channel; 29 | } 30 | 31 | // Channel(empty) 32 | function Channel(empty) { 33 | if (arguments.length > 1) 34 | throw new Error('Channel: too many arguments'); 35 | 36 | channel.$isClosed = false; // send stream is closed 37 | channel.$isDone = false; // receive stream is done 38 | channel.$recvCallbacks = []; // receive pending callbacks queue 39 | channel.$sendValues = []; // send pending values 40 | 41 | channel.empty = typeof empty === 'function' ? new empty() : empty; 42 | 43 | if (setProto) 44 | setProto(channel, Channel.prototype); 45 | else { 46 | channel.close = $$close; 47 | channel.done = $$done; 48 | channel.send = $$send; 49 | channel.recv = $$recv; 50 | 51 | // for stream 52 | channel.end = $$close; 53 | channel.stream = $$stream; 54 | 55 | if (channel.call !== Function.prototype.call) 56 | channel.call = Function.prototype.call; 57 | 58 | if (channel.apply !== Function.prototype.apply) 59 | channel.apply = Function.prototype.apply; 60 | } 61 | 62 | return channel; 63 | 64 | function channel(a, b) { 65 | // yield callback 66 | if (typeof a === 'function') 67 | return channel.recv(a); 68 | 69 | // error 70 | if (a instanceof Error) 71 | return channel.send(a); 72 | 73 | // value or undefined 74 | if (arguments.length <= 1) 75 | return channel.send(a); 76 | 77 | var args = slice.call(arguments); 78 | 79 | if (a == null) { 80 | if (arguments.length === 2) 81 | return channel.send(b); 82 | else 83 | args.shift(); 84 | } 85 | 86 | // (null, value,...) -> [value, ...] 87 | return channel.send(args); 88 | } 89 | 90 | } // Channel 91 | 92 | // send(val or err) 93 | Channel.prototype.send = $$send; 94 | function $$send(val) { 95 | if (this.$isClosed) 96 | throw new Error('Cannot send to closed channel'); 97 | else if (this.$recvCallbacks.length > 0) 98 | complete(this.$recvCallbacks.shift(), val); 99 | else 100 | this.$sendValues.push(val); 101 | } // send 102 | 103 | // recv(cb) 104 | Channel.prototype.recv = $$recv; 105 | function $$recv(cb) { 106 | if (this.done()) 107 | cb(null, this.empty); 108 | else if (this.$sendValues.length > 0) 109 | complete(cb, this.$sendValues.shift()); 110 | else 111 | this.$recvCallbacks.push(cb); 112 | return; 113 | } // recv 114 | 115 | // done() 116 | Channel.prototype.done = $$done; 117 | function $$done() { 118 | if (!this.$isDone && this.$isClosed && this.$sendValues.length === 0) { 119 | this.$isDone = true; 120 | // complete each pending callback with the empty value 121 | var empty = this.empty; 122 | this.$recvCallbacks.forEach(function(cb) { complete(cb, empty); }); 123 | } 124 | 125 | return this.$isDone; 126 | } // done 127 | 128 | // close() end() 129 | Channel.prototype.close = $$close; 130 | Channel.prototype.end = $$close; 131 | function $$close() { 132 | this.$isClosed = true; 133 | return this.done(); 134 | } // close 135 | 136 | // stream(stream) 137 | Channel.prototype.stream = $$stream; 138 | function $$stream(stream) { 139 | var channel = this; 140 | stream.on('end', close); 141 | stream.on('error', error); 142 | stream.on('readable', readable); 143 | return this; 144 | 145 | function close() { return channel.close(); } 146 | function error(err) { return channel.send(err); } 147 | 148 | function readable() { 149 | var buf = this.read(); 150 | if (!buf) return; 151 | channel.send(buf); 152 | } // readable 153 | } // stream 154 | 155 | // complete(cb, val or err) 156 | function complete(cb, val) { 157 | if (val instanceof Error) 158 | cb(val); 159 | else 160 | cb(null, val); 161 | } // complete 162 | 163 | if (typeof module === 'object' && module && module.exports) 164 | module.exports = Channel; 165 | 166 | })(); 167 | -------------------------------------------------------------------------------- /lib/trace.js: -------------------------------------------------------------------------------- 1 | // trace.js 2 | 3 | (function () { 4 | 'use strict'; 5 | 6 | function trace(fn, msg) { 7 | return function () { 8 | console.log(new Date().toISOString() + ' ' + msg + ' start ' + 9 | require('util').inspect([].slice.call(arguments),{colors:true})); 10 | var result = fn.apply(this, arguments); 11 | console.log(new Date().toISOString() + ' ' + msg + ' end'); 12 | return result; 13 | }; 14 | } 15 | 16 | exports = module.exports = trace; 17 | 18 | })(); 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aa", 3 | "version": "0.1.40", 4 | "description": "aa - async-await. co like library, go like channel, thunkify or promisify wrap package.", 5 | "main": "aa.js", 6 | "dependencies": { 7 | "promise-thunk": ">=0.1.16" 8 | }, 9 | "devDependencies": { 10 | "co": ">=4.6.0", 11 | "control-c": ">=0.0.9", 12 | "promise-light": ">=0.1.13" 13 | }, 14 | "keywords": [ 15 | "chan", 16 | "co", 17 | "channel", 18 | "thunkify", 19 | "go", 20 | "channel", 21 | "aa", 22 | "async", 23 | "async-await" 24 | ], 25 | "author": "LightSpeedC", 26 | "license": "MIT", 27 | "repository": { 28 | "type": "git", 29 | "url": "LightSpeedWorks/async-await" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/LightSpeedWorks/async-await/issues" 33 | }, 34 | "homepage": "https://github.com/LightSpeedWorks/async-await#readme", 35 | "scripts": { 36 | "test": "mocha" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/aa-readme-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | try { 4 | var aa = require('../aa'); 5 | } catch (e) { 6 | var aa = require('aa'); 7 | } 8 | 9 | var Promise = aa.Promise; 10 | 11 | var assert = require('assert'); 12 | 13 | 14 | var slice = [].slice; 15 | 16 | 17 | function clog() { 18 | console.log(' \x1b[36m' + slice.call(arguments).join(' ') + '\x1b[m'); } 19 | function cerr() { 20 | console.log(' \x1b[35m' + slice.call(arguments).join(' ') + '\x1b[m'); } 21 | 22 | 23 | // timed(done, ms, val) 24 | function timed(done, ms, val) { 25 | if (arguments.length < 3) val = new Error('time out'); 26 | var timer = setTimeout(function () { finish(val); }, ms); 27 | function finish(err, val) { 28 | if (timer) { 29 | clearTimeout(timer); 30 | timer = null; 31 | } 32 | done && done(err); 33 | done = null; 34 | } 35 | return finish; 36 | } 37 | 38 | // expectError(done) 39 | function expectError(done) { 40 | return function (err, val) { 41 | if (err instanceof Error) return done(); 42 | done(new Error('unexpected val: ' + val + (err == null ? '' : ' ' + err))); 43 | }; 44 | } 45 | 46 | // sleep(ms, args,... cb) : node style normal callback 47 | function sleep(ms) { 48 | var args = [].slice.call(arguments, 1), cb = args.pop(); 49 | if (ms >= 0) 50 | setTimeout.apply(null, [cb, ms, null].concat(args)); 51 | else 52 | setTimeout(cb, 0, new RangeError('sleep ms must be plus')); 53 | } 54 | 55 | 56 | // delay(ms, args,...)(cb) : thunk 57 | function delay(ms) { 58 | var args = [].slice.call(arguments); 59 | return function (cb) { 60 | sleep.apply(null, args.concat(cb)); 61 | }; 62 | } 63 | 64 | 65 | // aa(fn) | aa.wrap(fn) : returns wrapped function a.k.a thunkify and promisefy 66 | // wait(ms, args,...) : returns promise & thunk 67 | var wait = aa.promisify(sleep); 68 | 69 | 70 | describe('basic', function () { 71 | 72 | it('sleep 10', function (done) { 73 | done = timed(done, 30); 74 | sleep(10, done); 75 | }); 76 | 77 | it('sleep -1', function (done) { 78 | done = timed(done, 30); 79 | sleep(-1, expectError(done)); 80 | }); 81 | 82 | it('delay 10', function (done) { 83 | done = timed(done, 30); 84 | delay(10)(done); 85 | }); 86 | 87 | it('delay -1', function (done) { 88 | done = timed(done, 30); 89 | delay(-1)(expectError(done)); 90 | }); 91 | 92 | it('wait 10 thunk', function (done) { 93 | done = timed(done, 30); 94 | wait(10)(done); 95 | }); 96 | 97 | it('wait -1 thunk', function (done) { 98 | done = timed(done, 30); 99 | wait(-1)(expectError(done)); 100 | }); 101 | 102 | it('wait 10 promise', function (done) { 103 | done = timed(done, 30); 104 | wait(10).then(done, done).catch(done); 105 | }); 106 | 107 | it('wait -1 promise', function (done) { 108 | done = timed(done, 30); 109 | done = expectError(done); 110 | wait(-1).then(done, done).catch(done); 111 | }); 112 | 113 | }); // basic 114 | 115 | 116 | describe('aa generator', function () { 117 | 118 | it('yield primitive values, array and object', function (done) { 119 | done = timed(done, 100); 120 | 121 | // aa(generator) : returns promise & thunk 122 | aa(function *() { 123 | var v; 124 | 125 | // primitive value 126 | v = yield 123; 127 | assert.equal(v, 123); 128 | v = yield 'string'; 129 | assert.equal(v, 'string'); 130 | v = yield true; 131 | assert.equal(v, true); 132 | 133 | // array 134 | v = yield [1, 2, 3]; 135 | assert.deepEqual(v, [1, 2, 3]); 136 | 137 | // object 138 | v = yield {x:1, y:2, z:3}; 139 | assert.deepEqual(v, {x:1, y:2, z:3}); 140 | })(done); 141 | }); 142 | 143 | 144 | it('yield promises', function (done) { 145 | done = timed(done, 100); 146 | 147 | // aa(generator) : returns promise & thunk 148 | aa(function *() { 149 | var v; 150 | 151 | // wait for promise 152 | v = yield Promise.resolve(123); 153 | assert.equal(v, 123); 154 | try { 155 | v = yield Promise.reject(new Error('expected')); 156 | done(new Error('reject must throw')); 157 | } catch (err) { 158 | v = 234; 159 | } 160 | assert.equal(v, 234); 161 | 162 | })(done); 163 | }); 164 | 165 | 166 | it('yield thunks: delay', function (done) { 167 | done = timed(done, 100); 168 | 169 | // aa(generator) : returns promise & thunk 170 | aa(function *() { 171 | var v; 172 | 173 | // wait for thunk 174 | v = yield delay(2); 175 | assert.equal(v, undefined); 176 | v = yield delay(2, 11); 177 | assert.equal(v, 11); 178 | try { 179 | v = yield delay(-1, 12); 180 | done(new Error('delay -1 must throw')); 181 | } catch (err) { 182 | v = 13; 183 | } 184 | assert.equal(v, 13); 185 | 186 | })(done); 187 | }); 188 | 189 | 190 | it('yield promises and thunks: wait', function (done) { 191 | done = timed(done, 100); 192 | 193 | // aa(generator) : returns promise & thunk 194 | aa(function *() { 195 | var v; 196 | 197 | // wait for promise or thunk 198 | v = yield wait(2); 199 | assert.equal(v, undefined); 200 | v = yield wait(2, 22); 201 | assert.equal(v, 22); 202 | try { 203 | v = yield wait(-1, 23); 204 | done(new Error('wait -1 must throw')); 205 | } catch (err) { 206 | v = 24; 207 | } 208 | assert.equal(v, 24); 209 | })(done); 210 | }); 211 | 212 | it('yield Promise.all []', function (done) { 213 | done = timed(done, 100); 214 | 215 | // aa(generator) : returns promise & thunk 216 | aa(function *() { 217 | // yield Promise.all([]) 218 | var v = yield Promise.all([wait(20, 1), wait(30, 2), wait(10, 3)]); 219 | assert.deepEqual(v, [1, 2, 3]); 220 | })(done); 221 | }); 222 | 223 | it('yield []', function (done) { 224 | done = timed(done, 100); 225 | 226 | // aa(generator) : returns promise & thunk 227 | aa(function *() { 228 | // yield [] -> like Promise.all([]) ! 229 | var v = yield [wait(20, 4), wait(30, 5), wait(10, 6)]; 230 | assert.deepEqual(v, [4, 5, 6]); 231 | })(done); 232 | }); 233 | 234 | it('yield {}', function (done) { 235 | done = timed(done, 100); 236 | 237 | // aa(generator) : returns promise & thunk 238 | aa(function *() { 239 | // yield {} -> like Promise.all({}) !? 240 | var v = yield {x:wait(20, 7), y:wait(30, 8), z:wait(10, 9)}; 241 | assert.deepEqual(v, {x:7, y:8, z:9}); 242 | })(done); 243 | }); 244 | 245 | it('chan: sleep and yield', function (done) { 246 | done = timed(done, 100); 247 | 248 | // aa(generator) : returns promise & thunk 249 | aa(function *() { 250 | // make channel for sync - fork and join 251 | var chan = aa(); // or aa.chan() 252 | 253 | sleep(30, 20, chan); // send value to channel 254 | sleep(20, 10, chan); // send value to channel 255 | var a = yield chan; // recv value from channel 256 | var b = yield chan; // recv value from channel 257 | assert.equal(a, 10); 258 | assert.equal(b, 20); 259 | })(done); 260 | }); 261 | 262 | it('chan: fork and join', function (done) { 263 | done = timed(done, 100); 264 | 265 | // aa(generator) : returns promise & thunk 266 | aa(function *() { 267 | // make channel for sync - fork and join 268 | var chan = aa(); // or aa.chan() 269 | 270 | // fork thread - make new thread and start 271 | aa(function *() { 272 | yield wait(20); 273 | return 20; 274 | })(chan); 275 | 276 | // fork thread - make new thread and start 277 | aa(function *() { 278 | yield wait(10); 279 | return 10; 280 | })(chan); 281 | 282 | // fork thread - make new thread and start 283 | aa(function *() { 284 | yield wait(30); 285 | return 30; 286 | })(chan); 287 | 288 | // join threads - sync threads 289 | var x = yield chan; 290 | var y = yield chan; 291 | var z = yield chan; 292 | assert.equal(x, 10); 293 | assert.equal(y, 20); 294 | assert.equal(z, 30); 295 | })(done); 296 | }); 297 | 298 | 299 | it('chan: communication', function (done) { 300 | done = timed(done, 200); 301 | 302 | // aa(generator) : returns promise & thunk 303 | aa(function *() { 304 | // communicate with channels 305 | var chan = aa(), chan1 = aa(), chan2 = aa(); 306 | 307 | // thread 1: send to chan1, recv from chan2 308 | aa(function *() { 309 | sleep(2, 111, chan1); 310 | assert.equal(yield chan2, 222); 311 | sleep(2, 333, chan1); 312 | assert.equal(yield chan2, 444); 313 | sleep(2, 555, chan1); 314 | return 666; 315 | })(chan); 316 | 317 | // thread 1: recv from chan1, send to chan2 318 | aa(function *() { 319 | assert.equal(yield chan1, 111); 320 | sleep(2, 222, chan2); 321 | assert.equal(yield chan1, 333); 322 | sleep(2, 444, chan2); 323 | assert.equal(yield chan1, 555); 324 | return 777; 325 | })(chan); 326 | 327 | assert.equal(yield chan, 666); 328 | assert.equal(yield chan, 777); 329 | })(done); 330 | }); 331 | 332 | 333 | it('promise or thunk chain', function (done) { 334 | done = timed(done, 100); 335 | 336 | // aa(generator) : returns promise & thunk 337 | aa(function *() { 338 | return 11; 339 | }) 340 | .then( 341 | function (val) { 342 | //clog(11); 343 | assert.equal(val, 11); 344 | return wait(10, 22); }, 345 | function (err) { 346 | cerr('11 err:', err); 347 | done(err); } 348 | ) 349 | (function (err, val) { 350 | //clog(22); 351 | err && cerr('22 err: ', err); 352 | assert.equal(val, 22); 353 | return wait(10, 33); }) 354 | (function (err, val) { 355 | //clog(33); 356 | err && cerr('33 err: ', err); 357 | assert.equal(val, 33); 358 | return wait(10, 44); }) 359 | .then( 360 | function (val) { 361 | //clog(44); 362 | assert.equal(val, 44); 363 | return wait(10, 55); 364 | }, 365 | function (err) { 366 | cerr('44 err:', err); 367 | done(err); } 368 | )(done); 369 | 370 | }); 371 | 372 | }); // aa generator 373 | 374 | 375 | 376 | -------------------------------------------------------------------------------- /test/aa02-readme-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var aa = require('../aa02'); 4 | 5 | var Promise = aa.Promise; 6 | 7 | var assert = require('assert'); 8 | 9 | 10 | var slice = [].slice; 11 | 12 | 13 | function clog() { 14 | console.log(' \x1b[36m' + slice.call(arguments).join(' ') + '\x1b[m'); } 15 | function cerr() { 16 | console.log(' \x1b[35m' + slice.call(arguments).join(' ') + '\x1b[m'); } 17 | 18 | 19 | // timed(done, ms, val) 20 | function timed(done, ms, val) { 21 | if (arguments.length < 3) val = new Error('time out'); 22 | var timer = setTimeout(function () { finish(val); }, ms); 23 | function finish(err, val) { 24 | if (timer) { 25 | clearTimeout(timer); 26 | timer = null; 27 | } 28 | done && done(err); 29 | done = null; 30 | } 31 | return finish; 32 | } 33 | 34 | // expectError(done) 35 | function expectError(done) { 36 | return function (err, val) { 37 | if (err instanceof Error) return done(); 38 | done(new Error('unexpected val: ' + val + (err == null ? '' : ' ' + err))); 39 | }; 40 | } 41 | 42 | // sleep(ms, args,... cb) : node style normal callback 43 | function sleep(ms) { 44 | var args = [].slice.call(arguments, 1), cb = args.pop(); 45 | if (ms >= 0) 46 | setTimeout.apply(null, [cb, ms, null].concat(args)); 47 | else 48 | setTimeout(cb, 0, new RangeError('sleep ms must be plus')); 49 | } 50 | 51 | 52 | // delay(ms, args,...)(cb) : thunk 53 | function delay(ms) { 54 | var args = [].slice.call(arguments); 55 | return function (cb) { 56 | sleep.apply(null, args.concat(cb)); 57 | }; 58 | } 59 | 60 | 61 | // aa(fn) | aa.wrap(fn) : returns wrapped function a.k.a thunkify and promisefy 62 | // wait(ms, args,...) : returns promise & thunk 63 | var wait = aa.promisify(sleep); 64 | 65 | 66 | describe('basic', function () { 67 | 68 | it('sleep 10', function (done) { 69 | done = timed(done, 30); 70 | sleep(10, done); 71 | }); 72 | 73 | it('sleep -1', function (done) { 74 | done = timed(done, 30); 75 | sleep(-1, expectError(done)); 76 | }); 77 | 78 | it('delay 10', function (done) { 79 | done = timed(done, 30); 80 | delay(10)(done); 81 | }); 82 | 83 | it('delay -1', function (done) { 84 | done = timed(done, 30); 85 | delay(-1)(expectError(done)); 86 | }); 87 | 88 | it('wait 10 thunk', function (done) { 89 | done = timed(done, 30); 90 | wait(10)(done); 91 | }); 92 | 93 | it('wait -1 thunk', function (done) { 94 | done = timed(done, 30); 95 | wait(-1)(expectError(done)); 96 | }); 97 | 98 | it('wait 10 promise', function (done) { 99 | done = timed(done, 30); 100 | wait(10).then(done, done).catch(done); 101 | }); 102 | 103 | it('wait -1 promise', function (done) { 104 | done = timed(done, 30); 105 | done = expectError(done); 106 | wait(-1).then(done, done).catch(done); 107 | }); 108 | 109 | }); // basic 110 | 111 | 112 | describe('aa generator', function () { 113 | 114 | it('yield primitive values, array and object', function (done) { 115 | done = timed(done, 100); 116 | 117 | // aa(generator) : returns promise & thunk 118 | aa(function *() { 119 | var v; 120 | 121 | // primitive value 122 | v = yield 123; 123 | assert.equal(v, 123); 124 | v = yield 'string'; 125 | assert.equal(v, 'string'); 126 | v = yield true; 127 | assert.equal(v, true); 128 | 129 | // array 130 | v = yield [1, 2, 3]; 131 | assert.deepEqual(v, [1, 2, 3]); 132 | 133 | // object 134 | v = yield {x:1, y:2, z:3}; 135 | assert.deepEqual(v, {x:1, y:2, z:3}); 136 | })(done); 137 | }); 138 | 139 | 140 | it('yield promises', function (done) { 141 | done = timed(done, 100); 142 | 143 | // aa(generator) : returns promise & thunk 144 | aa(function *() { 145 | var v; 146 | 147 | // wait for promise 148 | v = yield Promise.resolve(123); 149 | assert.equal(v, 123); 150 | try { 151 | v = yield Promise.reject(new Error('expected')); 152 | done(new Error('reject must throw')); 153 | } catch (err) { 154 | v = 234; 155 | } 156 | assert.equal(v, 234); 157 | 158 | })(done); 159 | }); 160 | 161 | 162 | it('yield thunks: delay', function (done) { 163 | done = timed(done, 100); 164 | 165 | // aa(generator) : returns promise & thunk 166 | aa(function *() { 167 | var v; 168 | 169 | // wait for thunk 170 | v = yield delay(2); 171 | assert.equal(v, undefined); 172 | v = yield delay(2, 11); 173 | assert.equal(v, 11); 174 | try { 175 | v = yield delay(-1, 12); 176 | done(new Error('delay -1 must throw')); 177 | } catch (err) { 178 | v = 13; 179 | } 180 | assert.equal(v, 13); 181 | 182 | })(done); 183 | }); 184 | 185 | 186 | it('yield promises and thunks: wait', function (done) { 187 | done = timed(done, 100); 188 | 189 | // aa(generator) : returns promise & thunk 190 | aa(function *() { 191 | var v; 192 | 193 | // wait for promise or thunk 194 | v = yield wait(2); 195 | assert.equal(v, undefined); 196 | v = yield wait(2, 22); 197 | assert.equal(v, 22); 198 | try { 199 | v = yield wait(-1, 23); 200 | done(new Error('wait -1 must throw')); 201 | } catch (err) { 202 | v = 24; 203 | } 204 | assert.equal(v, 24); 205 | })(done); 206 | }); 207 | 208 | it('yield Promise.all []', function (done) { 209 | done = timed(done, 100); 210 | 211 | // aa(generator) : returns promise & thunk 212 | aa(function *() { 213 | // yield Promise.all([]) 214 | var v = yield Promise.all([wait(20, 1), wait(30, 2), wait(10, 3)]); 215 | assert.deepEqual(v, [1, 2, 3]); 216 | })(done); 217 | }); 218 | 219 | it('yield []', function (done) { 220 | done = timed(done, 100); 221 | 222 | // aa(generator) : returns promise & thunk 223 | aa(function *() { 224 | // yield [] -> like Promise.all([]) ! 225 | var v = yield [wait(20, 4), wait(30, 5), wait(10, 6)]; 226 | assert.deepEqual(v, [4, 5, 6]); 227 | })(done); 228 | }); 229 | 230 | it('yield {}', function (done) { 231 | done = timed(done, 100); 232 | 233 | // aa(generator) : returns promise & thunk 234 | aa(function *() { 235 | // yield {} -> like Promise.all({}) !? 236 | var v = yield {x:wait(20, 7), y:wait(30, 8), z:wait(10, 9)}; 237 | assert.deepEqual(v, {x:7, y:8, z:9}); 238 | })(done); 239 | }); 240 | 241 | it('chan: sleep and yield', function (done) { 242 | done = timed(done, 100); 243 | 244 | // aa(generator) : returns promise & thunk 245 | aa(function *() { 246 | // make channel for sync - fork and join 247 | var chan = aa(); // or aa.chan() 248 | 249 | sleep(30, 20, chan); // send value to channel 250 | sleep(20, 10, chan); // send value to channel 251 | var a = yield chan; // recv value from channel 252 | var b = yield chan; // recv value from channel 253 | assert.equal(a, 10); 254 | assert.equal(b, 20); 255 | })(done); 256 | }); 257 | 258 | it('chan: fork and join', function (done) { 259 | done = timed(done, 100); 260 | 261 | // aa(generator) : returns promise & thunk 262 | aa(function *() { 263 | // make channel for sync - fork and join 264 | var chan = aa(); // or aa.chan() 265 | 266 | // fork thread - make new thread and start 267 | aa(function *() { 268 | yield wait(20); 269 | return 20; 270 | })(chan); 271 | 272 | // fork thread - make new thread and start 273 | aa(function *() { 274 | yield wait(10); 275 | return 10; 276 | })(chan); 277 | 278 | // fork thread - make new thread and start 279 | aa(function *() { 280 | yield wait(30); 281 | return 30; 282 | })(chan); 283 | 284 | // join threads - sync threads 285 | var x = yield chan; 286 | var y = yield chan; 287 | var z = yield chan; 288 | assert.equal(x, 10); 289 | assert.equal(y, 20); 290 | assert.equal(z, 30); 291 | })(done); 292 | }); 293 | 294 | 295 | it('chan: communication', function (done) { 296 | done = timed(done, 200); 297 | 298 | // aa(generator) : returns promise & thunk 299 | aa(function *() { 300 | // communicate with channels 301 | var chan = aa(), chan1 = aa(), chan2 = aa(); 302 | 303 | // thread 1: send to chan1, recv from chan2 304 | aa(function *() { 305 | sleep(2, 111, chan1); 306 | assert.equal(yield chan2, 222); 307 | sleep(2, 333, chan1); 308 | assert.equal(yield chan2, 444); 309 | sleep(2, 555, chan1); 310 | return 666; 311 | })(chan); 312 | 313 | // thread 1: recv from chan1, send to chan2 314 | aa(function *() { 315 | assert.equal(yield chan1, 111); 316 | sleep(2, 222, chan2); 317 | assert.equal(yield chan1, 333); 318 | sleep(2, 444, chan2); 319 | assert.equal(yield chan1, 555); 320 | return 777; 321 | })(chan); 322 | 323 | assert.equal(yield chan, 666); 324 | assert.equal(yield chan, 777); 325 | })(done); 326 | }); 327 | 328 | 329 | it('promise or thunk chain', function (done) { 330 | done = timed(done, 100); 331 | 332 | // aa(generator) : returns promise & thunk 333 | aa(function *() { 334 | return 11; 335 | }) 336 | .then( 337 | function (val) { 338 | //clog(11); 339 | assert.equal(val, 11); 340 | return wait(10, 22); }, 341 | function (err) { 342 | cerr('11 err:', err); 343 | done(err); } 344 | ) 345 | (function (err, val) { 346 | //clog(22); 347 | err && cerr('22 err: ', err); 348 | assert.equal(val, 22); 349 | return wait(10, 33); }) 350 | (function (err, val) { 351 | //clog(33); 352 | err && cerr('33 err: ', err); 353 | assert.equal(val, 33); 354 | return wait(10, 44); }) 355 | .then( 356 | function (val) { 357 | //clog(44); 358 | assert.equal(val, 44); 359 | return wait(10, 55); 360 | }, 361 | function (err) { 362 | cerr('44 err:', err); 363 | done(err); } 364 | )(done); 365 | 366 | }); 367 | 368 | }); // aa generator 369 | 370 | 371 | 372 | -------------------------------------------------------------------------------- /tools/npm-publish.cmd: -------------------------------------------------------------------------------- 1 | node npm-publish 2 | @pause 3 | -------------------------------------------------------------------------------- /tools/npm-publish.js: -------------------------------------------------------------------------------- 1 | // npm-piblish 2 | 3 | (function () { 4 | 'use strict'; 5 | 6 | var aa = require('../aa'), promisify = aa.promisify; 7 | var fs = require('fs'); 8 | 9 | var fs_readFile = promisify(fs.readFile); 10 | var fs_writeFile = promisify(fs.writeFile); 11 | var child_process_exec = promisify(require('child_process').exec); 12 | 13 | aa(function *() { 14 | var pkgFile = '../package.json'; 15 | var releaseFile = 'release.json'; 16 | 17 | var obj = yield { 18 | pkg: readJSON(pkgFile), 19 | release: readJSON(releaseFile, {names: [], version: ''}) 20 | }; 21 | var pkg = obj.pkg, release = obj.release; 22 | 23 | if (pkg.version === release.version) 24 | return console.log('version', release.version, 'is already released'); 25 | 26 | release.version = pkg.version; 27 | if (!release.names) release.names = []; 28 | if (release.names.indexOf(pkg.name) < 0) 29 | release.names.unshift(pkg.name); 30 | yield writeJSON(releaseFile, release) 31 | 32 | for (var i in release.names) { 33 | pkg.name = release.names[i]; 34 | console.log(pkg.name, pkg.version); 35 | yield writeJSON(pkgFile, pkg); 36 | yield execCommand('cd .. & npm publish'); 37 | } 38 | 39 | }); 40 | 41 | // execCommand 42 | function *execCommand(cmd) { 43 | var res = yield child_process_exec(cmd); 44 | console.log(res[0]); 45 | res[1] && console.log(res[1]); 46 | } 47 | 48 | // readJSON 49 | function *readJSON(file, defaultObject) { 50 | try { 51 | return JSON.parse(yield fs_readFile(file, {encoding: 'utf8'})); 52 | } catch (e) { 53 | if (defaultObject === undefined) throw e; 54 | return defaultObject; 55 | } 56 | } 57 | 58 | // writeJSON 59 | function *writeJSON(file, obj) { 60 | yield fs_writeFile(file, JSON.stringify(obj, null, ' ') + '\n', {encoding: 'utf8'}); 61 | } 62 | 63 | })(); 64 | -------------------------------------------------------------------------------- /tools/release.json: -------------------------------------------------------------------------------- 1 | { 2 | "names": [ 3 | "async-await", 4 | "aa" 5 | ], 6 | "version": "0.1.40" 7 | } 8 | --------------------------------------------------------------------------------