Upgrade to Pro — share decks privately, control downloads, hide ads and more …

大阪Node学園 六時限目 「generator小咄」

大阪Node学園 六時限目 「generator小咄」

大阪Node学園 六時限目 「generator小咄」のスライドです

サンプルコードはgithubにあります
https://github.com/craftgear/ong6

Shunsuke Watanabe

September 05, 2013
Tweet

More Decks by Shunsuke Watanabe

Other Decks in Technology

Transcript

  1. Agenda 1. generator = 同期風コード? 2. generator ってなんだ 3. generator

    と iterator 4. 同期風コードの書き方 5. generator ベースのライブラリ群 6. generator を使うにあたって考慮したいこと 7. 今日のまとめ 8. 今後の予定 9. 参考文献 10. About the Author
  2. とあるブログにて node v0.12 (= node v1.0 ?) から generator が使えるよ

    うになるらしい。 ほほう、どれどれ ( ´_ ゝ` )
  3. ブログ記事の要約 (IMHO) ここに generator がある ゃろ? ( ^ω^ ) generator

    これをこうして … ( ^ω^ ) ≡ ≡ こう ゃ ( ^ω^ ) 同期っぽい!
  4. 関数の一種 generator もしくは generator 関数とも 通常の関数 ↓ generator function *

    ← アスタリスク重要 ! 途中で値を返すのには yield を使う function hoge() { return 'hoge'; } 1 2 3 function* hoge() { yield 'hoge'; } 1 2 3
  5. 戻り値が違う 通常の関数 実行結果 ↓ generator 実行結果 戻り値が iterator オブジェクト &

    iterator についてはのちほど' function hoge() { return 'hoge'; } var result = hoge(); console.log(result); 1 2 3 4 5 6 hoge 1 function* hoge() { yield 'hoge'; } var result = hoge(); console.log(result, typeof result); 1 2 3 4 5 6 {} object 1 https://github.com/craftgear/ong6/tree/master/example/01_return_value.js
  6. iterator は generator を操作するためのもの next() メソッドを呼び出すと yield まで処理が走って止まる 処理を再開するには再度 next()

    を呼ぶ サンプルコード iterator は generator のリモコン next() メソッドはリモコンの再生ボタン function* hoge(){ yield 1; yield 2; //return 3; } var iterator = hoge(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); 1 2 3 4 5 6 7 8 9 10 11 https://github.com/craftgear/ong6/tree/master/example/02_iterator.js
  7. next() で generator の内部状態がわかる next() の戻り値は value と done の二つのプロパティを持ったオ

    ブジェクト value ヹヹヹ yield の右側の値が入る done ヹヹヹ generator の最後に達するか、明示的に return 文 に出会うと true になる サンプルコード 実行結果 next() メソッドの戻り値で、 generator 内部の状 態がわかる function* hoge(){ yield 1; yield 2; //return 3; } var iterator = hoge(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); 1 2 3 4 5 6 7 8 9 10 11 { value: 1, done: false } { value: 2, done: false } { value: undefined, done: true } //return 3;のコメントアウトを外した場合 { value: 1, done: false } { value: 2, done: false } { value: 3, done: true } 1 2 3 4 5 6 7 8 https://github.com/craftgear/ong6/tree/master/example/02_iterator.js
  8. その逆も出来る generator 内部の状態を知るだけでなく、 next() メソッドで generator 内部の状態を操作できる サンプルコード 実行結果 next()

    メソッドに引数を渡すと、 generator に値 を送りこめる function* hoge(){ var x = null; console.log('inside generator: x is ', x); x = yield 1; console.log('inside generator: after yielded, x is ', x); } var iterator = hoge(); console.log('return value of next', iterator.next()); console.log('return value of next', iterator.next('hoge')); 1 2 3 4 5 6 7 8 9 10 11 inside generator: x is null return value of next { value: 1, done: false } inside generator: after yielded, x is hoge return value of next { value: undefined, done: true } 1 2 3 4 https://github.com/craftgear/ong6/tree/master/example/03_next.js
  9. next() を呼び出した時に起こること iterator 操作側: 10 行目 next() メソッドを呼び出す generator 内部:

    yield のある行 (4 行目 ) まで実行され、 yield の右側の値が戻り値の value プロパ ティとして返される 処理がここでとまる iteretor 操作側: 11 行目でふたたび next() メソッドを呼び 出す generator 内部: 先ほど止まった yield のある行 (4 行目 ) か ら実行が再開される。このとき、 next の引 数が yield 文の評価結果になる すなわち、 4 行目の yield 1 が hoge におき かわり、 x に hoge が代入される yield が返す値と yield 文の評価結 果、この二つの区別が大事
  10. iterator は generator のリモコン next() はリモコンの再生ボタン next() の戻り値は generator の内部状態

    next() メソッドに引数を渡すと、 generator 内部 に値を送り込める yield が返す値と yield 文の評価結果、この二 つの区別が大事
  11. コールバックスタイル var fs = require('fs'); fs.readFile( __dirname + '/ong6.txt' ,

    {encoding: 'utf-8'} , function (error, result) { console.log(result); process.exit(); } ); 1 2 3 4 5 6 7 8 9 10 https://github.com/craftgear/ong6/tree/master/example/04_async.js
  12. generator スタイル&仮' var fs = require('fs'); var fileReader = function*

    (callback){ var content = yield fs.readFile( __dirname + '/ong6.txt' , {encoding: 'utf-8'} , callback ); console.log('generator: ', content); process.exit(); } function run(generator){ var iterator = null; var callback = function(err, data) { if(err) iterator.throw(err); iterator.next(data); }; iterator = generator(callback); iterator.next(); } run(fileReader); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 同期風コード
  13. generator スタイル&仮'処理の流れ 1. 25 行目から処理開始 2. 21 行目で generator にコールバック用関数を渡して

    iterator 生成 3. 22 行目の iterator.next() で 4 行目の yield の右辺が実行され る 4. fs.readFile 処理が走り、 16 行目のコールバック用の関数に結 果が渡る 5. 18 行目で iterator.next を呼び出す、読み込んだファイルの中 身を引数に渡して呼び出す 6. 4 行目から処理が再開され、 result には読み込んだファイルの 中身が入る 7. 9 行目で結果を表示する 8. 10 行目で処理終了 https://github.com/craftgear/ong6/tree/master/example/05_sync.js
  14. generator で同期風コードを実現するには generator と iterator を操作するコードの二つが 必要 generator 内部のコード&自分が実行したい処理' iterator

    を回すコード& generator を制御するコード' の二つに分けて考えるようにするとわかりやすい + α の中身は iterator の操作コード
  15. suspend を使った同期風コード var suspend = require('suspend') , fs = require('fs');

    suspend(function* (resume){ try{ var content = yield fs.readFile( __dirname + '/ong6.txt' , {encoding: 'utf-8'} , resume ); console.log('generator: ', content); } catch(e){ console.log(e); } })(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 https://github.com/craftgear/ong6/tree/master/example/06_suspend.js
  16. suspend の特徴 generator を引数に渡して実行した後、再度実行する必要が ある (16 行目 ) node の標準コールバックスタイルがそのまま使える

    Promise とも併用できる スタックトリースでエラーを起こした yield 文の場所がわかる try catch するとエラーの場所がわからなくなる
  17. co を使った同期風コード var co = require('co') , fs = require('fs');

    var read = co.wrap(fs.readFile); co(function* (){ try{ var content = yield read( __dirname + '/ong6.txt' , {encoding: 'utf-8'} ); console.log('generator: ', content); } catch(e){ console.log(e); } }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 https://github.com/craftgear/ong6/tree/master/example/07_co.js
  18. co の特徴 呼び出す関数をラップするか、もしくは Thunk( 次ページ参照 ) にする必要がある & 4 行目'

    Promise とも併用できる generator を引数に渡すだけでよい スタックトリースでエラーの場所がわからない express のミドルイェア用モジュールがある TJ イェア
  19. Thunk ってなに? A "thunk" is also known as a "continuable"

    and is simply a function that accepts a node style callback as it's only argument. 訳: "thunk" は "continuable" ともいわれ、 node 形式のコールバックのみを引数として け る関数です。 gen-run の README.md より function sleep(ms) { return function (callback) { setTimeout(callback, ms); }; }
  20. genny を使った同期風コード var genny = require('genny') , fs = require('fs');

    //genny.longStackSupport = true; genny.run(function* (resume){ try{ var content = yield fs.readFile( __dirname + '/ong6.txt' , {encoding: 'utf-8'} , resume() ); console.log('generator: ', content); } catch(e){ console.log(e); } }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 https://github.com/craftgear/ong6/tree/master/example/08_genny.js
  21. genny の特徴 suspend と似ているが最後の関数実行は必要ない & 18 行目' そのかわりコールバック用関数を実行して渡す必要がある & 11

    行目' Thunk や Promise とも併用できる スタックトリースでエラーを起こした yield 文の場所がわかる try catch するとエラーの場所がわからなくなる longStackTrace オプションを有効にすると try catch してもエラ ーの場所がわかる ただし longStackTrace オプションはオーバーヘッドがすごい express のミドルイェアを generator にできる genny.middleware がある
  22. gen-run を使った同期風コード var run = require('gen-run') , fs = require('fs');

    run(function* (resume){ try{ var content = yield fs.readFile( __dirname + '/ong6.txt' , {encoding: 'utf-8'} , resume() ); console.log('generator: ', content); } catch(e){ console.log(e); } }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 https://github.com/craftgear/ong6/tree/master/example/09_gen-run.js
  23. gen-run の特徴 co と同 ような Thunk と suspend のようなコールバックスタイル の両方が使える

    スタックトリースでエラーを起こした yield 文の場所がわかる try catch するとエラーの場所がわからなくなる
  24. node の方針 by Isaac コールバックスタイルの理解は必須 The Future of Programming in

    Node.js "Callbacks will remain the de facto way to implement asynchrony. Generators and Promises are interesting and will remain a userland option." 訳: コールバックがデファクトの非同期実 装方法で在り続けます。ジェネリータやプロ ミスは興味深いですが、ユーザーランドの選 択肢のままです。
  25. ライブラリのオーバーヘッド genny の作者が書いたライブラリの比較記事 各ライブラリの実行速度、デバッグのしやすさなどあり ライブラリごとにばらつきはあるが、リクエストごとの処理時間で 160 %〜 400 %、メモリ使用量で 140%

    〜 240% のオーバーヘッ ドあり generator とは関係ないけど Promise ベースのライブラリが異常 に遅い オーバーヘッドあり Analysis of generators and other async patterns in node
  26. 今後の予定 大阪 Node 学園七時限目 ゼロから始める node.js 大阪 Node 学園八時限目 タイトル未定

    9/28 JAWS FESTA Kansai 2013 出張版 10/28 Innovation EGG 第一回勉強会 出張版
  27. イテリータとジェネリータ - JavaScript | MDN generators in v8 -- wingolog

    A Study on Solving Callbacks with JavaScript Generators A Closer Look at Generators Without Promises jmar777/suspend visionmedia/co spion/genny creationix/gen-run The Future of Programming in Node.js - Google グループ Analysis of generators and other async patterns in node
  28. About the Author 渡辺俊輔 フリーランス Web エンジニア 質問、訂正などは google+ 、

    twitter またはメールでどう google+ 大阪 node 学園 twitter@craftgear [email protected]