├── .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 | [](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 | [](https://nodei.co/npm/aa/)
23 | [](https://nodei.co/npm/aa/)
24 | [](https://nodei.co/npm/async-await/)
25 | [](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 |
--------------------------------------------------------------------------------