ループと非同期処理で変数の参照に気をつける

知ってる人には当たり前のことなどを。
ループ内で非同期処理をする際に、ループ内で有効な(i などのインデックスとか)変数を非同期処理のコールバックで参照しようとする期待したものと異なっていることがある。
こんなときの回避方法。

test.coffee

fs = require 'fs'

# ループで非同期処理をする失敗
for i in [0...100]
  fs.readFile './memo.txt', (err, data) ->
    console.log i, String(data), err

# 100 'test' null
# 100 'test' null
# 100 'test' null
# こんなのが出力される。i が 100 ではなく、連番になることを期待する場合、これはうまくない。

# ループで非同期処理をする正解
for i in [0...100]
  hoge = (i)->
    fs.readFile './memo.txt', (err, data) ->
      console.log i, String(data), err
  hoge i

# 0 'test' null
# 1 'test' null
# 2 'test' null
# 3 'test' null
# i がちゃんと連番になっている。連番を期待するのでこれで良い。

書いてしまえば当たり前なのだけれども、これを実装するためにループを回さずに再帰処理を書いたり、async の forEach 使おうとしたりいろいろまよった。

※下のループ内で関数をわざわざ定義する必要はないですね。ループ外で一度記述しておくほうがいいね。

参考URL