CoffeeScript
JSON
コールバック
fs.readFile

初心者にはこう説明してくれ!!coffeescriptのfs.readFileコールバック

例えばこんなコード。

loadCompletions: ->
      fs.readFile(
        path.resolve(__dirname, '..', 'completions.json'),
        (err, data) => @completions = JSON.parse(data) unless err?)

初心者はここに違和感を感じる

(err, data) => @completions = JSON.parse(data) unless err?

こんな説明はヤダ。

ググればすぐ出てくるよ。⇒本当に?
これは非同期で読み込んで引数にコールバック関数を指定しているんだよ。⇒はぁ?
javaから学び、直したほうがいいよ。⇒知らないし・・。

私ならこう説明されたい。

ポイントは2つあって「非同期、コールバック」なんだけど、聞いたことある?

このreadFile関数は非同期で実行されるように設計されているんだ。
例えば重たいファイルがあって、それを全部読み取らないと、次の画面に行ってくれないアプリだったら、ユーザーはイライラしてしまうだろ?そーゆうのを避けるために、非同期っていう思想があるんだ。
全部読み取らなくても、次に進むってことね。それを可能にするためにコールバックっていう概念があるんだ。
さっきの例で言ったアプリの場合だと、全部読み取らないで次の画面を出したら、動いている処理は、二つあることになるよね。

1、ファイル読み取り中⇒読み取り終了に向かう処理
2、ユーザーに次の画面を見せる処理

じゃデータ読み込み中はユーザーに画面見せて、他の事してもらうことにしよう。
それも終わって次の画面出したいけど、次に行くにはどうしてもさっき読み込み中だったデータが必要ってときはどうする?

画面をまた前に戻す。なんてしてたら、マジ切れされちゃうよね。
そうじゃなくて読み込み中の処理が全部終わったら、読み込んだデータを、次の画面に送るような機能をつければいいよね。
そうやって、非同期で実行された処理が終了した時点で実行する処理の事をコールバックっていうんだ。
プログラムでいうこれがその部分だよ。

(err, data) => @completions = JSON.parse(data) unless err?

今回は、unless err?でエラーがないかチェックして、JSON.parse(data)の結果を、loadCompletionsメソッドの外側にあるcompletions変数に格納しているよ。

(err, data)

このerrとdataはどこから来たかも気になるよね。
それはreadFile関数が、ファイルを読み取ったデータをdataに、エラーが出たらerrに入れてくれるんだよ。
まだ、あまり馴染みがない形かもしれないけど、関数自体が、結果を引数に入れて、さらにそれを引数である、コールバック関数に渡す形は、非同期処理によく出てくるから覚えておくといいよ。

あと、completionsの前についている「@」が、気になる?javaScriptのthisって言えばすぐわかるかな?
「->」じゃなくて「=>」なのが気になるなら、メソッド⇒関数⇒関数って構造が入れ子になっていくと、thisの状態も所々で変わってくるんだ。「=>」はそれを防ぐんだ。つまり前のthisを引き継いでいるって考えて。

で結局どうしてほしいかって?

1、目的を伝えてほしい。
なぜそれが必要になるのか、どうしてその形にしているのか。理解すると人は応用できるようになる。

2、例えてほしい。
  とても難しい概念でも、だいたいは身近なもので置き換えることができる。そうすれば人は容易に理解できるようになる。

3、実際に示してほしい。
コードのどの部分がそーゆう意味なのか、視覚に訴えて示してくれると、印象に残る。

4、それでもう一度詳しく説明してほしい。
そうすれば、要点が繰り返され、記憶に刻まれる。

5、察してほしい。
上級者は初心者がどんな分野でつまずくのか、知見があるはず。自分も初心者だったのだから。それを活かしてほしい。でも質問する側にも問題がある。自分がどこが分かっていないのかさえわからないようでは絶望的。でもどこがわからないのか親切に聞きだしてくれたら、初心者にとってはありがたい事に変わりはない。

6、考えさせる。
説明を受け身になっているだけだと、思考は停止する。本来人の思考速度はとても速いのだ。それを止めてはいけない。適切な質問をして考えを確認し、思考を導けば良い結果につながる。