それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Promiseを使って画像のロード待ちに対応する

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();