Qiitaからの移動


Atomのプラグインを書こうとして,CoffeeScriptを書いていたらPromiseの使用中にハマった. もう既に誰かが踏んだ地雷な気がするし,Qiitaに記事があると思ったが,見つからなかったのでメモがてら残しておく.

やりたい事とコード

CoffeeScriptを使って,次のようなPromiseの使用をしたかった.

  1. thenの引数関数内で,メンバへのアクセスをする
  2. thenの引数関数内で,resolverejectを使う

then内で,非同期APIの結果の例外処理(JSON,DOMのパースなど)をして,さらに,成功時はメンバへアクセスして処理をするような感じで,例えば,次のようなコード(Promiseの必要がないコードだが,例という事で)

class Class
  n: 2

  func: ->
    new Promise(
      (resolve) -> resolve(10)
    ).then(
      (value) ->
        if value is 0
          reject("value is 0")
        else
          resolve(value * @n)
    ).then((value) -> console.log(value + " #result"))

が,これを動かすと,@nundefinedとなり(CoffeeScriptの仕様への自分の理解が正しければ当然),コンソールにはNaN #resultが表示されてしまう.

こういうcallbackを簡単にかくために,CoffeeScriptには=>という記法があるので,これを使うと次のように書ける.

class Class
  n: 2

  func: ->
    new Promise(
      (resolve) -> resolve(10)
    ).then(
      (value) =>
        if value is 0
          reject("value is 0")
        else
          resolve(value * @n)
    ).then((value) -> console.log(value + " #result"))

しかし,今度はUncaught (in promise) ReferenceError: resolve is not definedというエラーメッセージが表示される. あまりちゃんと調べていないが,resolveは,this.resolveの意味であり,=>によってthisの動きが変わっているのだろう.

実験

どういうふうに書けば適切な動作をするのかを調べるべく,書き方を思いつく限り試して見た所,次のような結果になった.結局,new Promiseを使って記述するのが今回の場合は最善なのかな.

上手く動くコード

then((value) -> value)
then((value) => value * @n)
then((value) => new Promise((resolve, reject) => resolve(value * @n))

メンバにアクセス出来ずに変な動作をするコード

then((value) -> value * @n)

ReferenceErrorが起こるコード

(value) => resolve(value * @n)

最後に

他にもっと簡単な解決策があれば教えて頂けると嬉しいです.CoffeeScriptは触り始めたばっかりなので.