caolan/asyncã使ã£ãNode.jsã®ããã¼å¶å¾¡
JavaScript Advent Calendar 2011 (Node.js/WebSocketsコース)ã®16æ¥ç®ã§ãã
@koichikããã®13日目の記事ã«ãæ¸ããã¦ããããã«ãNode.jsã«ã¦éåæå¦çã管çããæ¹æ³ã«ã¯ä»¥ä¸ã®2種é¡ãããã¾ã
- éåæå¦çã®å¼ã³åºãæã«ã³ã¼ã«ããã¯é¢æ°ãä¸ãããå¦çãçµãã£ããã¨ã©ã¼ã®æç¡ã¨ãçµæãéç¥ãããã
- EventEmitterã«å¯¾ãã¦on/onceã§EventListenerãã»ãããã¦éåæå¦çãå®è¡ãããéåæå¦çã®å®è¡ã«ãã£ã¦çºçããã¤ãã³ããã¨ã©ã¼ã¯ãªã¹ãã¼ã«éç¥ãããã
å¾è ã®èª¬æã¯koichikããã®è¨äºã«ãä»»ããã¦ããã®è¨äºã¯åè ãæ±ãã©ã¤ãã©ãªcaolan/asyncã«ã¤ãã¦ã¿ã¦ããããã¨æãã¾ãã
caolan/asyncã£ã¦ï¼
https://github.com/caolan/async ã§å
¬éããã¦ããããã¼å¶å¾¡ã©ã¤ãã©ãªã§ãã
èªåã¯Node.jsã§ä½¿ã£ã¦ãã¾ããããã©ã¦ã¶ä¸ã§åãJavaScriptãæ¸ãå ´åã«ã使ç¨ã§ããããã§ãã
https://github.com/joyent/node/wiki/modules#wiki-async-flowã«è¨è¼ããã¦ããNode.jsç¨ããã¼å¶å¾¡ã¢ã¸ã¥ã¼ã«ã¯æ¢ã«50ãè¶
ãã¦ãã¾ããã試ãã¦ã¿ãä¸ã§ã¯ä¸çªä½¿ããããã¢ã¸ã¥ã¼ã«ã§ããã
# ãããã«50ãã¹ã¦ã¯è©¦ãã¦ããªãã§ããgithubã®watcheræ°1000ãªã¼ãã¼ãfolkæ°62ã¨ãããã¨ã§å°ãªãã¨ãããã¼å¶å¾¡ã¢ã¸ã¥ã¼ã«ã®æå¤§æã§ã¯ããã¯ãã
asyncãå®ç¾ãã¦ãããããã¼å¶å¾¡ã®ä¸é¨ã¯ã¾ãã«「非同期プログラミングの改善」のエッセンスã®å 容ãªã®ã§ãå ã«èªãã§ããã¨çè§£ãæ·±ã¾ããã¨æãã¾ãã
ä½ããã¦ãããï¼
asyncããã£ã¦ãããå¦çã«ã¯æ§ã
ãªãã®ãããã¾ãããã¾ãã¯async#seriesãä¾ã«ãã¦èª¬æãã¦ããããã¨æãã¾ãã
hogeãã£ã¬ã¯ããªãæã£ã¦ãpiyoãã£ã¬ã¯ããªãæã£ã¦ããã®ä¸ã«ãã¼ã¿ãæ¸ãã ãã³ã¼ããã³ã¼ã«ããã¯ã使ã£ã¦æ¸ãã¨ä»¥ä¸ã®ããã«ãªãã¾ãã
(ãã£ã¬ã¯ããªå ã¯å帰çã«ãã£ã¦ãããã¢ã¸ã¥ã¼ã«ãããã¾ããè¦ãªãã£ãæ¹åã§)
var fs = require('fs'); fs.mkdir('./hoge', function(err) { if(err) { // ã¨ã©ã¼å¦ç return; } fs.mkdir('./hoge/piyo', function(err) { if(err) { // ã¨ã©ã¼å¦ç return; } fs.writeFile('./hoge/piyo/neko', 'Hello Node.js', function(err) { if(err) { // ã¨ã©ã¼å¦ç return; } console.log('success'); }); }); });
ãã®ä¾ã®ããã«ãéåæå¦çã®çµäºãå¾
ã£ã¦ããæ¬¡ã®å¦çããããå ´åããã¹ããæ·±ããªããã¨ã©ã¼å¦çããã¡ãã¡ã«åæ£ããã¨ãã£ãåé¡ç¹ãããã¾ãã
ã§ã¯ããã®ã³ã¼ããasyncã使ã£ãå½¢ã§æ¸ãç´ãã¦ã¿ã¾ãããã
var fs = require('fs'); var async = require('async'); var tasks = []; tasks.push(function(next) { fs.mkdir('./hoge', next); }); tasks.push(function(next) { fs.mkdir('./hoge/piyo', next); }); tasks.push(function(next) { fs.writeFile('./hoge/piyo/neko', 'Hello Node.js', next); }); async.series(tasks, function(err, results) { if(err) { // ã¨ã©ã¼å¦ç return; } console.log('success'); console.log(results); // [undefined, undefined, undefined] });
ã¯ããã¨ã©ã¼å¦çãä¸ã«æã«ã¾ã¨ã¾ãã¾ããã
ãã¹ããæ·±ããªããã¨ããªããå¦çãtasksã«ã¾ã¨ã¾ã£ã¦ãã¦è¯ãæãã§ãã
async#seriesã¯ç¬¬ä¸å¼æ°ã§ä¸ããããtasksã®å¦çãé çªã«å®è¡ãã¦ãããã¡ã½ããã§ãã
tasksã«æ ¼ç´ãããåå¦çã¯ãèªåã®å¦çãçµãã£ãæç¹ã§next()ãå¼ã³åºãããã¨ã©ã¼ã®æç¡ãã¨ãèªåã®å¦ççµæããéç¥ãã¾ãã
ã¨ã©ã¼ãçºçããªãã£ãå ´åã«ã¯èªåçã«æ¬¡ã®å¦çãå¼ã³åºããã ã¨ã©ã¼ãçºçããå ´åã«ã¯ãããããå
ã®å¦çã¯å®è¡ãããã«async.seriesã®ç¬¬äºå¼æ°ã«æ¸¡ããã颿°ãå¼ã³åºããã¾ãã
errã«ã¯çºçããã¨ã©ã¼ï¼ã¨ã©ã¼ãªãã®å ´åã¯nullï¼ãå
¥ããresultsã«ã¯åå¦çã®å¦ççµæãã¾ã¨ãã¦å
¥ãã¾ãã
ä»å使ã£ãfs#mkdirãfs#writeFileã¯ã¨ã©ã¼ã®æç¡ã®ã¿ãéç¥ããçºãresultsã«é¢ãã¦ã¯æ¬¡é
ã®ä¾ãè¦ã¦ããã£ãæ¹ãåããããããã¨æãã¾ãã*1
async#series, async#parallel
asyncã¢ã¸ã¥ã¼ã«ã«ã¯series以å¤ã«ãæ§ã
ãªã¡ã½ãããç¨æããã¦ãã¾ãã
ããããã¯ããããã®å¦çã®æµããå³ã§è¡¨ããªããç°¡åã«èª¬æãã¦ããããã¨æãã¾ãã
ã¾ãã¯async#seriesã§ãã
å
ã»ã©èª¬æããéããä¸ã¤ã®å¦çãçµãã£ã¦ããæ¬¡ã®å¦çãè¡ãããããããã®å¦ççµæãendã«éç´ããã¦ãã¾ãã
å¡ä¾ï¼
ã»éãåè§ï¼å¦ç
ã»èµ¤ãåè§ï¼ãã¼ã¿
ã»éç·ï¼å¦çã®æµã
ã»èµ¤ç·ï¼ãã¼ã¿ã®æµã
ã»finishï¼async#****ãå¼ã³åºãã¨ãã«ä¸ããããcallback颿°
(ã¨ã©ã¼çºçæããå ¨é¨ã®å¦çãçµãã£ãå¾ã«å¼ã°ãã颿°)
ï¼ å³ã¯Cacooã«ã¦ä½æãExcelã¯å³ãæããã¼ã«ã§ã¯ãªãã®ã§ãã
ã¤ã¥ãã¦ãasync#parallelããã¡ãã¯å
¨é¨ã®å¦çãåæã«å®è¡ããããã¹ã¦ãçµãã£ãæç¹ã§endãå¼ã°ãã¾ãã
ãã®å ´åãseriesã¨åãããããããã®å¦ççµæã¯endã«éç´ããã¦ãã¾ãã
async#seriesã¨async#parallelã®éããè¦ãããã«ãdelayããªç§å¾ ã£ã¦ããtextã®å 容ãåºåããå¦ççµæã¨ãã¦resultãè¿ã颿°ããä½ã£ã¦è©¦ãã¦ã¿ã¾ãã
function delayedPrint(delay, text, result) { return function(next) { setTimeout(function() { util.log(text); next(null, result); }, delay); } } var tasks = []; tasks.push(delayedPrint(3000, 'test1', 'result1')); tasks.push(delayedPrint(2000, 'test2', 'result2')); tasks.push(delayedPrint(1000, 'test3', 'result3'));
async#seriesã®å ´å
util.log('start'); async.series(tasks, function(err, results) { util.log('true end'); console.log(results); }); util.log('end? ... NO. while processing.');
å®è¡çµæï¼
16 Dec 01:39:13 - start 16 Dec 01:39:13 - end? ... NO. while processing. 16 Dec 01:39:16 - test1 16 Dec 01:39:18 - test2 16 Dec 01:39:19 - test3 16 Dec 01:39:19 - true end [ 'result1', 'result2', 'result3' ]
async#parallelã®å ´å
util.log('start'); async.series(tasks, function(err, results) { util.log('true end'); console.log(results); }); util.log('end? ... NO. while processing.');
å®è¡çµæï¼
16 Dec 01:40:15 - start 16 Dec 01:40:15 - end? ... NO. while processing. 16 Dec 01:40:16 - test3 16 Dec 01:40:17 - test2 16 Dec 01:40:18 - test1 16 Dec 01:40:18 - true end [ 'result1', 'result2', 'result3' ]
ãããã®çµæãã以ä¸ã®ãã¨ãåããã¾ãã
- end?ã®æç¹ã§ã¯ã¾ã å¦çãçµãã£ã¦ããªããå ¨é¨ã®å¦çãçµäºããã®ã¯true endã®æç¹ã
- startããendã¾ã§ã®æéãseriesã§ã¯ç´åå®è¡ã®çºã3 + 2 + 1 = 6ç§
- startããendã¾ã§ã®æéãparallelã§ã¯ä¸¦åå®è¡ã®çºã§ãmax(3, 2, 1) = 3ç§
- parallelã®ä¾ãè¦ãã¨ãããããã«resultsã«å ¥ã£ã¦ããã®ã¯å¦çã®å®äºé ã§ã¯ãªãtasksã®é
async#waterfall
async#waterfallãå³ã«è¡¨ãã¨ä»¥ä¸ã®ããã«ãªãã¾ãã
å¦çã®æµãèªä½ã¯seriesã¨åçã§ãããseriesã¨éããå¦ççµæãæ¬¡ã®å¦çã«ä¸ãããã¾ãã
便å©ãªã¡ã½ããã§ãããã¨ã¯ç¢ºããªã®ã§ããããã®ã¡ã½ããã«é¢ãã¦ã¯æ°ã«ãªã£ã¦ãããã¨ãããçºã徿¥æ¹ãã¦ã¨ã³ããªãèµ·ãããã¨æãã¾ãã
async#forEach, async#forEachSeries
åé
ã§ç´¹ä»ããseries, parallel, waterfallã¯è¤æ°ã®å¦çã®æµããå¶å¾¡ããå½¢ã§ããããé
åã®åè¦ç´ ã«å¯¾ãã¦åãå¦çãå®è¡ãããã¨ãè¯ãããã¾ãã
åæå¦çã§ããã°Array#forEachã使ãã°ããã®ã§ããããã®ä¸ã«éåæå¦çãå«ã¾ãã¦ããå ´åãArray#forEachããå¦çãè¿ã£ãæç¹ã§ã¯é
åã®åè¦ç´ ã«å¯¾ããå¦çãçµãã£ã¦ãã¾ããã
asyncã§ã¯ãããã£ãå ´åã«ä½¿ããã¡ã½ããã¨ãã¦forEach, forEachSeriesã¨ããã¡ã½ãããç¨æãã¦ãã¾ãã
ååããããããããã«forEachã¯ä¸¦åå¦çãè¡ããforEachSeriesã¯ç´åã«å¦çãè¡ãã¾ãã
async#map, async#mapSeries
forEachãforEachSeriesã¯é
åã®åè¦ç´ ã«å¯¾ãã¦å¦çãè¡ãã¾ãããå¦ççµæãè¿ãæ©è½ã¯æã£ã¦ãã¾ããã
é
åã®è¦ç´ ã夿ãããå ´åãªã©ã«ã¯Array#mapã¨åãããasync#mapãç¨ãã¾ãã
ãããforEachã¨åããasync#mapã¨async#mapSeriesã®äºã¤ãç¨æããã¦ããããã夿ãã¸ãã¯ã®éãã«å¿ãã¦å¥½ããªæ¹ãé¸ã¶ãã¨ãã§ãã¾ãã
ã»ãã®é¢æ°
ä»åã¯ç´¹ä»ãããã¾ããã§ããããcaolan/asyncã«ã¯ä»ã«ã以ä¸ã®ãããªã¡ã½ãããæä¾ãã¦ãã¾ãã
- makeãã¡ã¤ã«ã®ããã«åã¿ã¹ã¯ã«åææ¡ä»¶ãæå®ããã¨ãèªåçã«é çªãçµã¿ç«ã¦ã¦ãããauto
- forEach/mapã®ããã«Arrayãæä¾ãã¦ããå¦çããã£ã¦ãããfilter, filterSeries, reject, rejectSeries, reduce, reduceRight, concat, concatSeries, some, any, every, all
- æ¡ä»¶ãæºããé or æºããã¾ã§å¦çãç¶ããwhilst, until
- 並åã§å®è¡ããæå¤§æ°ãæå®ãã¦å¤§éã®ã¿ã¹ã¯ãå¦çãããããqueue
- éãå¦çã®å¦ççµæãèªåçã«ãã£ãã·ã¥ãã¦äºåç®ä»¥éã®å¼ã³åºãã軽ãããmemoize
ãããã®ã¡ã½ããã¨EventEmitterããã¾ã使ããã¨ã§å¦çã®æµããæ´çããå¦çã®æµããåãããããã³ã¼ããç®æãã¾ãããï¼
ææ¥ã¯@n_matsuiããã§ãã
*1:ä¾é¸ã³ã«å¤±æããæãã²ãã²ãã¨






