deferred.el のできるまで:調査、設計と実装

deferred.elを作る上での参考にした情報や、設計・実装のメモです。
一般的なDeferredの理解や、Deferredの情報まとめとしても使えるかもしれません。

Deferredについて

  • コールバックをうまく書くイディオム
  • 非同期処理の抽象化の道具
  • 汎用性が高く、使い始めると無いと困るレベル

後述のbrazilさんの記事が大変オススメです。

参考にした情報など

基本的に古い記事(2年以上前)が多く、JavaScript界の中ではすでにブームは過ぎ去って、常識の域になっているようです。そうは言っても、deferred.elを実装するために過去のブックマークなどを掘り起こして読み直してみたのですが、自分の中では再発見することも多かったです。

JSDeferred

deferred.elで一番参考にした実装です。実装がシンプルです。
後述のMochikit.AsyncのDeferredに触発されてできたようです。

Mochikit.Async / Twisted

JSDeferredの次に参考にした実装です。機能が豊富です。
Pythonの非同期フレームワークTwistedからの移植のようです。

その他

みんな非同期や遅延リソースの取り扱いに困っているようで、Deferredにはいろいろな実装があります。

設計

いろいろ見た結果、JSDeferredがコード量が少ないながら、十分なインタフェースを備えているようでしたので、JSDeferredをインタフェースと実装のお手本にすることにしました。また、結果の待ち合わせについてはMochikit.Asyncから雰囲気で持ってきました。

すこし残念なのは、Emacs Lisp では JSDeferred にあったようなメソッドチェーンが出来ないことなのですが、ある程度コードの中で目立って、書きやすそうなマクロ(deferred:$)を用意することでカバーすることにしました。

実装

何度かJSDeferredのコードを読んだことがあったので、先にテストを書いてみて、うろ覚えで実装してみました。そうすると、当然ながら仕様の勘違いがいくつかあったのですが、それが元でさらにDeferredを深く理解するきっかけになりました。

テストについては、るびきちさんの el-expectations.el を使いました。こういうライブラリ的なものについてはかなり役立ちます。非同期のテスト対象にはそのまま使えなかったので、マクロでなんとかしました。そのためテスト自体は厳密ではないのですが、それでもかなりのバグを抑えることが出来たと思います。

el-expectaions.el については、どこでエラーが失敗したのかをexpectに説明を書くなどして分かりやすくしたいとか、expectのコードの途中でチェックするためにassertも書けるとテストコードが減ってうれしいなと思いました。

deferred.elはそれほど長くなくて、しかもコアの部分はdeferredオブジェクトを回しているところだけなので、読める人はおもしろいのではないかなと思います(実際に作っていておもしろかったので)。



これで、deferred.elが出来るまでシリーズは終わりです。
次回は、Deferredと一緒に出てくる継続とか遅延実行などについてのもやもやについて、考えてみたことを書いてみます。