非同期処理を同期処理っぽく扱う
まず、以下2つの関数を用意しました。
// funcBの戻り値と"funcA"を吐き出す関数 function funcA(){ console.log(funcB()); console.log("funcA"); } // 開始から5秒後に「funcB」とreturnする関数 function funcB(){ setTimeout(function(){ return "funcB"; },5000); }
期待としては、実行から5秒後に「funcB」と「funcA」が
(ほぼ)同時に表示されてほしいわけですが、まあそういうわけにはいきません。
setTimeoutは「5秒後に○○という処理をする」というタイマー的なものをセットしているだけなので。
具体的には、実行と(ほぼ)同時に
undefined funcA
と表示されます。
その5秒後くらいにfuncBが返している値は闇に消えます。
ここまで簡単な例ならsetTimeout内で「funcB」「funcA」を表示すりゃいいじゃん、で済みますが
複雑になってくると困る場合もあったので、いろいろ調べて以下のように加筆修正してみました。
// funcBの戻り値と"funcA"を吐き出す関数 function funcA(){ var def = funcB(); def.done(function(){ console.log(def.return_value); console.log("funcA"); }); } // 開始から5秒後に「funcB」とreturnする関数 function funcB(){ var deferred = new $.Deferred(); setTimeout(function(){ deferred.return_value = "funcB"; deferred.resolve(); },5000); return deferred; }
わーいらくちーん
deferredというのを使っています。
処理を監視して、「終了したら○○する」ということができます。
無事に、実行後5秒ほど経ってから
funcB funcA
と表示されました。
ポイントは以下のような感じでしょうか。
- funcA
- funcBの戻り値を変数で受けて、「.done」で「funcB終了時の処理」を記述
- funcB
- Deferredオブジェクトを生成し、resolve()で処理終了したことを通知
- Deferredオブジェクトのreturnは、時間のかかる処理の外でOK
- Deferredオブジェクトには戻り値用の要素を勝手に追加できる
- 上記の例では「return_value」が勝手に追加したやつ
これなら大元のロジックを大きく変えることなく実装できそう。