islands5 blog

日々起こったことを共有したり、思ったこと、勉強したことを書いていくブログ。普段はRailsやAWSを活用したWeb系の開発をやってます。

Promiseオブジェクトを使ったらAPI周りの処理がスッキリした

f:id:fiveislands:20180125213553p:plain

かなり前からPromiseオブジェクトの存在は知ってたのですが、ほとんど気にしないでほったらかし状態に...
ただ、必要な状態に出会ってしまったのと、そのときに初めてPromiseについて便利さが理解できた気がするので共有します

先に結論
要件: リクエストした内容を特定の要素のhtml内に入れるという処理を行う
よくやること: APIへのアクセスのcallbackに要素の変更に関するコードを入れる
対応: Promiseを使ってやれば、APIへのアクセスと要素の変更をキレイに分離でき、可読性も上がって嬉しい!!
という内容です

最終的なコードは

function requestHogeAPI(){
  return Promise.new (function(resolve, reject) {
    $.ajax({
      url: "/api/v1/hoge"
    })
    .done(function(res){
       resolve(res);
    })
    .fail(function(e){
       reject(e);
     });
  })
}

// main
requestHogeAPI()
.then(function(data){
  $("#hoge").html(data)
})
.catch(function(e){
  console.log(e)
})

上記のコードは、APIへのアクセスと要素の変更が別の処理にわかれてます。
このコードに至るまでに僕が辿った道筋をまとめてみました。

未知との遭遇(jsビギナースタイル)

// resは<div>hello world</div>が帰ってくるイメージです
function fugaSetResponse() {
  $.ajax({
    url: "/api/v1/hoge"
  })
  .done(function(res){
    $("#fuga").html(res);
  })
  .fail(function(e){
    console.log(e);
   });
}


//main
fugaSetResponse()

ajaxのレスポンスにjqueryが直接書いてるパターン
大なり小なり、よくあるコードなんじゃないかな?と思います。
みんなここを一度は通りますよね?よね???(俺だけ???)

抽象化1(セレクタスタイル)

function elemementSetResponse(elem){
  $.ajax({
    url: "/api/v1/hoge"
  })
  .done(function(res){
    $(elem).html(res)
  })
  .fail(function(e){
    console.log(e)
  });
}

//main
elementSetResponse("#piyo")

セレクタを引数として渡してそいつに適用するパターン
まだapiと要素の変更が一緒になってて、気持ちわるい

抽象化2(コールバックスタイル)

hogeapiへのリクエスト結果に他の処理を加えたい

function elementProcessor(callbackFunc){
  $.ajax({
    url: "/api/v1/hoge"
  })
  .done(function(res){
    callbackFunc(res)
  })
  .fail(function(e){
    console.log(e)
  });
}

function changeHoge(res){
  $("#hoge").html(res);
}

//main
elementProcessor(changeHoge)

与える関数を変更すれば要素も変更できるし、処理も変更できるし少しうれしい感じ
あとなんかjsっぽいw
...changeHogeは他のところで使うのだろうか??
無名関数渡してもいいよね

抽象化3(コールバックセレクタスタイル)

こちらは僕が最初書こうとしてたコード

function elementProcessor(callbackFunc, elem){
  $.ajax({
    url: "/api/v1/hoge"
  })
  .done(function(res){
    callbackFunc(res, elem)
  })
  .fail(function(e){
    console.log(e)
  });
}

function changeElement(res, elem){
  $(elem).html(res);
}

//main
elementProcessor(changeElement, "#piyo")

ただ、callbackに渡すために親に引数追加ってちょっとやり過ぎじゃね?って思ったんですよね

抽象化4(やっぱりプロミス!!)

function requestHogeAPI(){
  return Promise.new (function(resolve, reject) {
    $.ajax({
      url: "/api/v1/hoge"
    })
    .done(function(res){
       resolve(res);
    })
    .fail(function(e){
       reject(e);
     });
  })
}

// main
requestHogeAPI()
.then(function(data){
  $("#hoge").html(data)
})
.catch(function(e){
  console.log(e)
})

thenの中は好きなコード書いてOK
requestHogeAPIのコードはわりと色んなところで使用できると思うし、役割の分割もきっちり出来てると思う。

結論

Promiseを使って上手くやれば、APIへのアクセスと要素の変更をキレイに分離できて関数の再利用性が上がるし可読性も上がって嬉しい!!

ではではm( )m