読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

コールバックを介して値を取得する関数を配列の要素毎に適応するための関数

配列の要素毎に関数を適用するmapは記述を簡潔してとても便利です。でも、ネットワークを介してデータを取得するなどコールバックされた時に値がわかる場合には使えません。

なので、そのための関数を作ってみました。
(jQueryのDeferredを使っています。)

asyncMap = (array, asyncFunc, extractResult, interval, success, fail) ->
    results = new Array array.length
    deferredes = ($.Deferred() for e in array)
    $.when.apply(this, deferredes).then (-> success results), (-> fail results)
    for e, i in array
        ((e, i) ->
            setTimeout (-> asyncFunc e, ->
                console.log arguments
                try
                    results[i] = extractResult.apply this, arguments
                    deferredes[i].resolve()
                catch e
                    deferredes[i].reject()
            ), interval * i
        )(e, i)


testAsync = (element, callback) ->
    setTimeout (-> callback element), 0

testExtract = (e) -> e

asyncMap [0...10], testAsync, testExtract, 0, ((results) -> console.log results), ((results) -> console.log 'fail')

asyncMapの引数arrayは対象とする配列、asyncFuncは非同期の関数で

async 要素, コールバック

で呼び出されることを仮定しています。例として$.getなどを思い浮かべてください。仮定した引数の取り方をしない場合、ラッパー関数を作成して対応します。

extractResultにはコールバックされた時に必要な結果を抽出し、エラーがあれば例外を発生させる関数です。
何も処理する必要がない場合には、恒等関数(e) -> eでかまいませんので何か用意してください。

intervalはasyncFuncを呼び出す間隔(ms)です。例えば、Google Maps APIなど一定時間でのアクセス回数に制限があるようなAPIを利用する場合、間隔を開けて使います。

successは配列全体のmapが終わった時に呼び出される関数です。ここで終了処理を行います。

failはextractResultが例外を起こした時に呼び出される関数です。エラー処理します。