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

Node, Promises and Functional Programming

Node, Promises and Functional Programming

東京Node学園 8時限目 ”Nodeとプロミスと、時々、関数型” by @okapies
http://connpass.com/event/2125/

Yuta Okamoto

April 25, 2013
Tweet

More Decks by Yuta Okamoto

Other Decks in Programming

Transcript

  1. ୭ʁ • Ԭຊ ༤ଠ (@okapies) • Java/Scala ϓϩάϥϚ • ؔ਺ܕϓϩάϥϛϯάमߦத…

    • ٕज़จॻͷ຋༁Λ͍͔ͭ͘΍ͬͯ·͢ • Effective Scala (http://twitter.github.io/effectivescala/ index-ja.html) • “Scala Conference in Japan 2013” ຋༁νʔϜ
  2. ”ωετ஍ࠈ (Pyramid of Doom)”͸ຊ࣭Ͱ͸ͳ͍ step1(function (value1) { step2(value1, function(value2) {

    step3(value2, function(value3) { step4(value3, function(value4) { // ... }); }); }); });
  3. ྫ: ෳ਺ͷϑΝΠϧΛฒྻతʹ fs.stat ͯ͠ mtime ΛऔΓग़͢ɻ file1 file2 file3 stat

    mtime stat stat mtime mtime ฒྻॲཧ શͯͷ݁Ռ͕ ἧͬͨΒ࣍΁
  4. var async = require('async'), fs = require('fs'); var paths =

    ['file1.txt', 'file2.txt', 'file3.txt']; async.map(paths, fs.stat, function(error, stats) { // stats Λ࢖͏ }); file1 file2 file3 stat mtime stat stat mtime mtime OK!
  5. var paths = ['file1.txt', 'file2.txt', 'file3.txt']; async.map(paths, fs.stat, function(error, stats)

    { // stats Λ࢖͏ }); fs.stat(paths[0], function(error, stat) { // stat.size Λ࢖͏ }); file1 file2 file3 stat mtime stat stat mtime mtime file1 stat size ೋ౓ΞΫηεͯͯ͠ޮ཰͕ѱ͍… file1 ͷ size ΛऔΓग़͢ॲཧΛ௥Ճ
  6. ਖ਼͍͠ॱংͰɺ͔ͭޮ཰ྑ͘ॲཧͰ͖Δ ίʔυΛॻ͖͍ͨɻ file1 file2 file3 stat mtime stat stat mtime

    mtime size ֤ϑΝΠϧ͸Ұ౓͚ͩΞΫηε͢Δ file1 ͕औಘͰ͖ͨΒશͯͷstat ͕ἧͬͯͳͯ͘΋ॲཧ͢Δ
  7. var paths = ['file1.txt', 'file2.txt', 'file3.txt'], file1 = paths.shift(); async.parallel([

    function(callback) { fs.stat(file1, function(error, stat) { // stat.size Λ࢖͏ callback(error, stat); }); }, function(callback) { async.map(paths, fs.stat, callback); } ], function(error, results) { var stats = [results[0]].concat(results[1]); // stats Λ࢖͏ }) Oh...
  8. ໋ྩܕϓϩάϥϛϯά • Ͳ͏΍Δ͔ (how) Λɺ໋ྩγʔέϯεΛ໌ࣔతʹهड़ ͯ͠Ϛγϯʹ఻͑Δɻ ؔ਺ܕϓϩάϥϛϯά • ԿΛͯ͠΄͍͔͠ (what)

    Λ”஋ಉ࢜ͷؔ܎”ʹΑͬͯه ड़͠Ϛγϯʹ఻͑Δɻ • ίϯϐϡʔλ͸”஋ಉ࢜ͷؔ܎”͔Β໋ྩγʔέϯεΛ ܭࢉ͢Δɻ
  9. function func(in) { return /* in ͔Β out Λܭࢉ */;

    } out = func(in) ”out ͸ in ʹґଘ͍ͯ͠Δ”ͱಡΊΔ ؔ਺ ஋Λೖྗͯ͠ɺม׵ͯ͠ɺ஋Λग़ྗ͢Δ ग़ྗ͸ೖྗʹʢͷΈʣґଘ͢Δ ʹ
  10. ؔ਺ͷग़ྗΛ ผͷؔ਺ͷೖྗ΁ͱܨ͛ͯ ॲཧͷύΠϓϥΠϯΛ࡞Δ function f(in) { return /* in ͔Β

    out Λܭࢉ */ } function g(in) { return /* in ͔Β out Λܭࢉ */ } out = g(f(in)) f ͷग़ྗΛ g ʹೖྗ͢Δ ಉ༷ʹ”out ͸ in ʹґଘ͍ͯ͠Δ”ͱಡΊΔ
  11. var fs_stat = promisify(fs.stat); var paths = ['file1.txt', 'file2.txt', 'file3.txt'];

    var statsPromises = paths.map(fs_stat); file1 file2 file3 stat stat stat fs_stat ݁Ռ͸ϓϩϛε ͱ͍͏ശʹೖΔ String ͷ഑ྻ͔Βϓϩϛεͷ഑ྻΛ࡞Δ
  12. // promisify :: (a -> (Error -> b -> ())

    -> ()) -> (a -> Promise b) var promisify = function(fn, receiver) { return function() { var slice = Array.prototype.slice, args = slice.call(arguments, 0, fn.length - 1), promise = new Promise(); args.push(function() { var results = slice.call(arguments), error = results.shift(); if (error) promise.reject(error); else promise.resolve.apply(promise, results); }); fn.apply(receiver, args); return promise; }; } ίʔϧόοΫ൛͔Βϓϩϛε൛Λ࡞Δϔϧύʔؔ਺
  13. var statsPromises = paths.map(fs_stat); statsPromises[0].then(function(stat) { /* stat.size */ });

    then() Λ࢖͏ͱϓϩϛεʹґଘ͢Δ ผͷඇಉظॲཧΛهड़Ͱ͖Δ file1 stat size ϓϩϛεΛ࡞Δ fs_stat then(function(stat)->...) ശ͔Β஋ΛऔΓग़͠ ؔ਺ʹ༩͑Δ
  14. stat mtime stat stat mtime mtime ”ϓϩϛεͷϦετ”Λ ”Ϧετʹର͢Δϓϩϛεʹ”ม׵ stat stat

    stat var statsPromises = paths.map(fs_stat); list(statsPromises).then(function(stats) { /* stats */ }); ଴ͪ߹Θ͕ͤՄೳʹʂ list() then()
  15. // list :: [Promise a] -> Promise [a] var list

    = function(promises) { var listPromise = new Promise(); for (var k in listPromise) promises[k] = listPromise[k]; var results = [], done = 0; promises.forEach(function(promise, i) { promise.then(function(result) { results[i] = result; done += 1; if (done === promises.length) promises.resolve(results); }, function(error) { promises.reject(error); }); }); if (promises.length === 0) promises.resolve(results); return promises; }; ϓϩϛεͷϦετʹ then() Λ௥Ճ͢Δϔϧύʔؔ਺
  16. var fs_stat = promisify(fs.stat); var paths = ['file1.txt', 'file2.txt', 'file3.txt'],

    statsPromises = list(paths.map(fs_stat)); statsPromises[0].then(function(stat) {/* stat.size Λ࢖͏ */}); statsPromises.then(function(stats) {/* stats Λ࢖͏ */}); file1 file2 file3 list(paths.map(fs_stat)) stat stat stat size mtime mtime mtime ґଘؔ܎ͷهड़ͷΈͰ ஞ࣍ॲཧ΋ฒྻॲཧ΋࣮ݱͰ͖͍ͯΔʂ
  17. Mikeal Rogersࢯͷ൓࿦ • ”ϓϩϛεΛ࢖ͬͨ API ͸ɺͦΕ͕Ͳ͏ ಈ࡞͢Δ͔Λௐ΂Δඞཁ͕͋Δɻ” • ”then() ΍

    list() ͸ҙຯ࿦ΛӅṭ͢Δͷ Ͱɺೝ஌తෛՙ͕େ͖͍ɻ” from http://www.futurealoof.com/posts/broken-promises.html
  18. James Coglanࢯͷ࠶൓࿦ • ”ϓϩϛε͕ easy Ͱ͋Δ͔͸ॏཁͰͳ ͍ɻsimple Ͱ͋Δ͔Λ໰͏΂͖ɻ” • ”΍Γ͍ͨ͜ͱ͕มΘͬͨ࣌ʹίʔυͷ

    มߋ͕গͳ͘ࡁΉɻϓϩϛε͸ɺίϨ Ϋγϣϯ΍ඇಉظੑ΍࣮ߦॱংͱ͍ͬ ͨ֓೦ͱ෼཭Ͱ͖Δ͔Βͩɻ” from http://blog.jcoglan.com/2013/04/01/callbacks-promises-and-simplicity/