Async Enhancement
Grand-Frontend-Osaka 2015 Summer
2015.8.22
自己紹介
• かみやん (Twitter@kamiyam)

http://nantokaworks.com

• 主にJavaScriptでお仕事をしている人
• カメラ/自動車
Engineer
AGENDA
• JavaScriptと非同期処理
• 非同期の強みと弱み
• 非同期処理実行のエンドポイント
• ライブラリコールバック
• 非同期処理中のエラーハンドリング
• 複数非同期処理のコールバック
AGENDA
• 非同期処理実行時のscopeのお話
• Promise
• 革命的だった async モジュール
• Promise準拠
• Q
• まとめ
JavaScriptと非同期処理
同期処理
2sec
5sec
1sec
同期処理
2sec
5sec
1sec
2sec
5sec
非同期処理
1sec
2sec
5sec
非同期処理
1sec
非同期の強みと弱み
// sorry node.js code
var fs = require(“fs”);
// Sync read directory
var files = fs.readdirSync(“.”);
console.log(files);
console.log(“conmplate”);
// Async read directory
fs.readdir(“.", function(err, files){
if (err) throw err;
console.log(files);
});
console.log(“complate…?”);
プログラムのメインフローを邪魔せず
非同期で処理をnon blockingで実行
(する代わりに人が追いにくい流れに)
ドミノ倒しを想像するとわかりやすい
非同期処理実行の
エンドポイント
// document ready
$(function(){
var $target = $(".initAnimetion”);
$target.fadeIn( "slow", function() {
setTimeout(function(){
$target.fadeOut( "slow", function() {
console.log( "completed!!!" );
})
}), 2*1000 ); //2秒待つ
});
});
非同期の処理が終わった時に
実行されるコールバック関数が必要
ライブラリコールバック
処理終了後の振る舞いは
利用者に委ねなければならない
=コールバック関数が常に必要
// example
(function($){
$.mySuperElegantLibrary = (function(){
var hoge = “”;
var fuga = “”;
return {
miracleMethod: function(arg1,cb){
if(typeof(arg1) === 'function') cb = arg1;
if((cb == null)) cb = $.noop;
},
specialMethod: function(arg1,cb){
if(typeof(arg1) === 'function') cb = arg1;
if((cb == null)) cb = $.noop;
}
}
})();
})(jQuery);
変数 cb は関数なのか文字列なのか
undefinedなのかそうじゃないのか…
つきまとうコールバックとの闘い
非同期処理中の
エラーハンドリング
JavaScript にも try…catch あります
// example catching error
(function(){
try{
throw new Error("エラーです");
}catch(e){
console.log(e);
console.log("ここで正しい処理をします")
}
})();
// example catching error…???
// callback method inner is wonder land
(function(){
try{
setTimeout(function(){
throw new Error("エラーです");
},1000);
}catch(e){
console.log(e);
console.log("ここでただしい処理をしますし(時間差)");
}})();
oh……
複数非同期処理の
コールバック
// async methods
var A = function(cb){
setTimeout(function(){
cb("1秒掛かる処理を実行しました");
},1000);
};
var B = function(cb){
setTimeout(function(){
cb("5秒掛かる処理を実行しました");
},5000);
};
var C = function(cb){
setTimeout(function(){
cb("2秒掛かる処理を実行しました");
},2000);
};
MISSION
処理A,B,C それぞれの結果を
A,B,Cの順に配列に入れよ
//oh! very easy
var result =[];
A(function(message1){
console.log(message1);
result.push(message1);
B(function(message2){
console.log(message2);
result.push(message2);
C(function(message3){
console.log(message3);
result.push(message3);
console.log("全ての処理がおわりました");
console.log(result);
});
});
});
同期処理
2sec
5sec
1sec
同期処理
2sec
5sec
1sec
// parallels
var allRequest = [A,B,C];
var result =[];
var counter = allRequest.length;
allRequest.forEach(function(request,i){
console.log(i); // 0,1,2
request(function(message){
// Message出力(単体)
console.log(message);
result[i] = message;
console.log(i); //0,2,1 <—-?
if(--counter == 0){
// Message出力(全体)
console.log("全ての処理がおわりました");
console.log(result);
}
});
});
2sec
5sec
非同期処理
1sec
2sec
5sec
非同期処理
1sec
直列同期処理
処理内容 処理時間
処理①
処理②
処理③
完了
直列同期処理
処理内容 処理時間
処理①
処理②
処理③
※ 前述サンプルのような処理の結果を以って

次の処理を行う場合は別
同時に実行出来る処理は実行してしまいたい
完了
並列同期処理
処理内容 処理時間
処理①
処理②
処理③
完了
並列同期処理
処理内容 処理時間
処理①
処理②
処理③
完了
それぞれの処理を同時に実行し、一番遅い処理が

完了するまで他は待機
ここで一旦話は変わり…
非同期処理実行時の
scopeのお話
JavaScript ループで回した時、
最後の方の要素しかなんか動かない問題
// no problem
(function($){
$(function(){
// display none
$("#content").children().hide();
//forEach
$("#content").children().each(function(i,item){
// show
$(item).fadeIn("slow");
})
})
})(jQuery)
// no problem
(function($){
$(function(){
// display none
$("#content").children().hide();
//forEach
$("#content").children().each(function(i,item){
// show
setTimeout(function(){
$(item).fadeIn("slow");
}, i * 1000);
})
})
})(jQuery)
大丈夫そう
// problems happen…
// why!!! JavaScript looping!!
(function($){
$(function(){
// display none
$("#content").children().hide();
var children = $("#content").children();
for(var i=0; i < children.length; i++){ //for loop
// show
setTimeout(function(){
var item = children[i];
$(item).fadeIn("slow");
}, i * 1000);
}
})
})(jQuery)
// changing code…
(function($){
$(function(){
// display none
$(“#content”).children().hide();
var show = function(i){
// show
setTimeout(function(){
var item = children[i];
$(item).fadeIn("slow");
}, i * 1000);
}
var children = $("#content").children();
for(var i=0; i < children.length; i++){ //for loop
show(i)
}
})
})(jQuery)
// before parallels process
var allRequest = [A,B,C];
var result =[];
var counter = allRequest.length;
for(var i=0; i<allRequest.length; i++){
console.log(i); // 0,1,2
allRequest[i](function(message){
// Message出力(単体)
console.log(message);
result[i] = message;
console.log(i); //3,3,3 <- !!!
if(--counter == 0){
// Message出力(全体)
console.log("全ての処理がおわりました");
console.log(result);
}
});
}
くろーじゃー…
Promise
複数の非同期処理の最後
もうちょっとなんとかなりませんか?
成功と失敗への遷移の確約
Promises/A+
https://promisesaplus.com/
https://developer.mozilla.org/ja/docs/Web/JavaScript/
Reference/Global_Objects/Promise
MDN Promise
http://caniuse.com/#feat=promises
Can I Use
try~catchはエラーの確約だったはず…
// promise…then…catch
var promise = new Promise(function(resolve,reject){
// example async progress
doSomhing(function(error, data){
if(error) return reject(error);
resolve(data);
})
});
promise.then(function(data){
// with success
}).catch(function(error){
// fail…
})
// parallel…then…catch
var promise1 = new Promise(function(resolve,reject){
// example async progress
doSomhing(function(error, data1){
if(error) return reject(error);
resolve(data1);
})
});
var promise2 = new Promise(function(resolve,reject){
// 省略
resolve(data2)
});
Promise.all([promise1,promise2]).then(function(result){
// with success
console.log(result); // [data1,data2]
}).catch(function(error){
// fail…
})
resolve / reject に
結果の約束を結びつける
革命的だった async モジュール
(私の中では)
async.waterfall([function(next){
console.log(“1”);
setTimeout(function(){
console.log(“1 complete”);
next(null, 1); //next(error, result);
},3000);
},function(next){
console.log(“2”)
setTimeout(function(){
console.log(“2 complete”);
next(null, 2); //next(error, result);
},3000);
}], function(err, result1, result2 ){
console.log(err); // …null
console.log(result1); //…1
console.log(result2); //…2
});
async. parallel([function(callback){
console.log(“1”);
setTimeout(function(){
console.log(“1 complete”);
callback(null, 1); //arg1…error,arg2….result
},3000);
},function(next){
console.log(“2”)
setTimeout(function(){
console.log(“2 complete”);
callback(null, 2);
},1000);
}], function(err, result){
console.log(err); // …null
console.log(result); //…[“1”,”2”]
});
Promise準拠
JavaScript Promises ※ 公開日 2013/12/16
http://www.html5rocks.com/ja/tutorials/es6/promises/
Conformant Implementations
https://promisesaplus.com/implementations
Q
// promise…then…catch
var promise = function(){
var deferred = q.deferred();
// example async progress
doSomething(function(error, data){
if(error) return deferred.reject(error);
deferred.resolve(data);
})
return deferred.promise;
});
promise.then(function(result){
// with success
console.log(result); // data
}).catch(function(error){
// fail…
})
// parallel…then…catch
var promise1 = function(){
var deferred = q.deferred();
// set deferred.reject(data1) & deferred.resolve(error)
return deferred.promise;
});
var promise2 = function(){
var deferred = q.deferred();
// set deferred.reject(data2) & deferred.resolve(error)
return deferred.promise;
});
q.all([promise1(), promise2()]).then(function(result){
// with success
console.log(result); // [data1,data2]
}).catch(function(error){
// fail…
})
まとまらないまとめ
非同期処理が複数実行される時、
その実行と完了を追うことが非常に重要
Promise準拠ライブラリをうまく使い分
けて半同期処理的なアプローチを
他にGenerator /Yield もあるよ
参考
• JavaScriptと非同期のエラー処理

http://techblog.yahoo.co.jp/programming/javascript_error/
• あなたの知らない JavaScript Promise

https://gist.github.com/kuu/e182d361520e70a158c9
• Effective ES6

http://www.slideshare.net/teppeis/effective-es6
ご清聴ありがとうございました

Async Enhancement