JavaScriptでコールバック連結 (1)

 2012年11月からスタートした本ブログも、めでたく今週で20記事目を迎えました。今後とも株式会社CFlatをよろしくお願いいたします。

 さて、本題へ。
 JavaScriptは、登場直後である1990年代中頃を除けば、言語自体の機能としてはさほど大きな変化を経験してはいない言語の側に分類できるでしょう。
 にもかかわらず、それを取り巻くライブラリーや実行環境の進化は、JavaScriptをしてこの上なく様変わりした言語たらしめています。このことはJavaScript単体のみならず、HTML、そしてWebというもの過言ではないのではないでしょうか?

 さて、このJavaScriptの変革に大きく寄与したキーワードは、皆様(少なくとも名前くらいは)ご存知『Ajax』。動的にサーバー上のリソースを読み込み、ページの状態を更新することにより、以前よりあったDHTML技術を「コンテンツの表示/非表示を制御するだけのツール」から「Webアプリケーション」へと変革させたブレイクスルーといえます。
 一方で、Ajax技術はそれだけでは、単一のリソースを読み込むことはできても、複数のリソースを協調的に読み込むことには慣れていません。例えば、次のようなケースを考えます。

・ボタンが表示される
・ボタンを押すと、スロットが回り始める
・スロットはしばらくすると止まるが、当たるか外れるかはサーバー側の結果によって決まる
・結果に応じたアニメーションを表示する
・結果にかかわらず、特定のページに遷移する

 ……はい、よくあるWeb懸賞の仕組みですね。これを、より詳しく見ていくとしましょう。

(1) ボタンを表示するためのアニメーションを実行する
(2) スロットアニメーションを読み込む
(3) (1)の完了後、ボタンが押されるのを待つ
(4) (3)が完了したら、サーバー上のAPIに、当たるか外れるかの結果を問い合わせる
(5) (3)が完了して(2)が未完了であれば、ローディング表示を行う
(6) (3)と(2)が完了したら、もしローディング表示があれば消し、スロットアニメーションを表示する
(7) (4)が完了したら、結果に応じたアニメーションを読み込む
(8) (6)が完了して(7)が未完了であれば、ローディング表示を行う
(9) (6)と(7)が完了したら、もしローディング表示があれば消し、結果アニメーションを表示する
(10) (9)が完了したら、特定のページに遷移する

 ご覧の通り、かなり複雑です。
 もちろん、アニメーションを最初に全て読み込んでおくことにすればはるかに簡易にはなるのですすが、その分、ユーザーが操作できるようになるまでの時間がかかってしまいます(通常、このような処理はFlashが担当するため、必要なアニメーションは全てswf内に圧縮して持っておけばよいのですが)。
 そんなわけでこれをJavaScriptで実装するためには、ボタン表示のアニメーション中にスロットアニメーションを読み込んでしまうなどの工夫を駆使しつつ、保守性を犠牲にしながらユーザーの快適な操作を目指すわけです。

 そして、これをさらに面倒にさせるのが、それぞれの処理が非同期処理であるという事実。setTimeout()やらjQuery.ajax()やら。
 いずれにせよ、「この処理が終わったらこの処理を……」という単純な連結を、あらかじめコールバック関数を与えて呼んでもらう、という形で書いてやらねばなりません。漫然と無名関数で次の処理、次の処理、と書いていると、段々とインデントが悲惨なことに……。

 とにかく面倒なので、こういうのを簡単に実装するためのライブラリーでも作ってしまいましょう、というのが今回の記事の動機というわけでした。非同期処理の連結用ライブラリとしてはjQuery.DefferedやPot.jsが存在するようですが、上記のようなかなり混乱した処理を行うのはどうしても煩雑になってしまいます。
 なら、自作してみましょうか、ということで次回へ続きます。