jQuery.Deferred 風の非同期処理ライブラリを CoffeeScript で書いてみた

jQueryソースコードを読むのが日課の今日このごろ、みなさんはいかがお過ごしですか?

Deferred は、連鎖した非同期処理を楽にしてくれるライブラリだ。以下のエントリを読むと概要がわかる。

爆速でわかるjQuery.Deferred超入門 - Yahoo! JAPAN Tech Blog
結局jQuery.Deferredの何が嬉しいのか分からない、という人向けの小話 - Qiita

jQuery の ready イベントはどういうふうに処理されているのか、ソースコードを追っているうちにぶち当たったのが、この Deferred ライブラリ。ソースコードをいくら読んでもよく理解できない。理解できない理由は、

  • 無名関数が何重にもネストされている
  • そのため変数名がどの値に束縛されているのかよくわからない
  • さらに jQuery.extend を使って混乱に輪をかけている

など。たぶん非常に頭がいい人なら理解できるのだろうが、私には無理だった。

ソースに対する断片的理解と Deferred の仕様から、自分なりに Deferred 風のライブラリを書いてみた。CoffeeScript で書くと期待以上にコードが美しかったので、Github で公開してみた

こんな感じで使う。

delay = (ms, task) ->
  setTimeout task, ms

x = []

task1 = ->
  df = new Deferred()
  delay 100, ->
    x.push(1)
    df.reject()
  df.promise()

oktask = ->
  d = new Deferred()
  delay 100, ->
    x.push(2)
    d.resolve()
  d.promise()

ngtask = ->
  d = new Deferred()
  delay 100, ->
    x.push(-2)
    d.reject()
  d.promise()

task2 = -> x.push(3)
task3 = -> x.push(4)

task1().then(oktask, ngtask).done(task2).fail(task3)

delay 300, ->
  expect(x).toEqual([1, -2, 4])