JavaScript はマルチスレッドプログラムで、コールバック地獄
JavaScript はマルチスレッドプログラムで、コールバック関数を作るのがメインの作業だと思います。 マルチスレッドプログラムは構わないんだけど、コールバック関数の管理が面倒。特に変数。
まぁこのテの話題は耳タコなのでコレ以上触れないけど
addEventListener 系のコールバックは苦痛
document.addEventListener("DOMContentLoaded",function(){ var a document.querySelector("a.images"); var img = new Image(); img.src = "my_image.jpg" img.addEventListener("load", function(){ a.appendChild(img) }) })
jQueryに頼らず、DOM+JSで書こうとすると、やっぱり長いよねぇ。
Promiseで非同期処理をまとめて待つ。
jQuery.deffered とか、Futurerパターンと同じですが。
Promise
画像のロードを待って何かする処理
Promiseを使って、処理の記述を後回しにする。
var i = new Promise(function(resolver,rejector){ var img = new Image(); img.src = "my_image.jpg"; img.addEventListener("load", function(){ resolver(this) }) img.addEventListener("error",function(){ rejector(this) }) }) Promise.all( i ).then(function(value){ // var img = value console.log( img ) })
これで後回しにするができる。けど、コレでも十分コールバック地獄なんですが。。。
スレッドの同期
読み込みスレッドを複数同期するとこんな感じ
var i = new Promise(function(resolver,rejector){ var img = new Image(); img.src = "my_image.jpg"; img.addEventListener("load", function(){ resolver(this) }) img.addEventListener("error",function(){ rejector(this) }) }) var c = new Promise(function(resolver,rejector){ var img = new Image(); img.src = "my_image2.jpg"; img.addEventListener("load", function(){ resolver(this) }) img.addEventListener("error",function(){ rejector(this) }) }) Promise.all( [ i ,c ] ).then(function(values){ //2本待ち var img = value[0] console.log( img ) var img = value[1] console.log( img ) })
これで、2つの画像のロード(スレッド)の完了町をして処理することが出来る。
順番に処理する
順番に処理するには、これは簡単。
var a = new Promise(function(resolve){ console.log(1) resolve() }).then(function(resolve){ console.log(2) resolve() });
これを、実際にすると、以下のようになる。
var a = new Promise(function(resolver){ var img = new Image(); img.src = "my_image1.jpg"; img.addEventListener("load", function(){ resolver(this) }) img.addEventListener("error",function(){ rejector(this) }) }).then(function(resolver){ var img = new Image(); img.src = "my_image2.jpg"; img.addEventListener("load", function(){ resolver(this) }) img.addEventListener("error",function(){ rejector(this) }) });
これで、順番通りに処理することが出来る
一つだけ問題点
Promiseは、引数の関数をすぐに実行してしまう。つまり、次のようなコードが有るときに、 new Promise した時点で settimeout の実行は開始してて、Promise.all する前に結果は決まっている。
var p = new Promise( function( resolve, reject ) { //ここは即実行 setTimeout(resolve, 1000); })
たとえば、任意のタイミングでPromise(Thread)起動したいとき、先にPromiseを作るための関数を作って、その関数を実行してPromiseする関数を作らないと厄介かもしれないな。
var pre_promise = { "f" : function(res,rej){ res() }, "start" : function( ) { return new Promise(this.f) } } pre_promise.v = function(res){ setTimeout(res, 1000) } var p = pre_promise.start();