Slide 1

Slide 1 text

Nodeͱϓϩϛεͱ ࣌ʑɺؔ਺ܕ @okapies

Slide 2

Slide 2 text

୭ʁ • Ԭຊ ༤ଠ (@okapies) • Java/Scala ϓϩάϥϚ • ؔ਺ܕϓϩάϥϛϯάमߦத… • ٕज़จॻͷ຋༁Λ͍͔ͭ͘΍ͬͯ·͢ • Effective Scala (http://twitter.github.io/effectivescala/ index-ja.html) • “Scala Conference in Japan 2013” ຋༁νʔϜ

Slide 3

Slide 3 text

ܦҢ

Slide 4

Slide 4 text

Java VMͷ ੩తܕ෇͖ݴޠ ΦϒδΣΫτࢦ޲ʴؔ਺ܕ

Slide 5

Slide 5 text

ඇಉظRPCϥΠϒϥϦ”Finagle” Scala ͷ Node.jsʂ Tumblr, 4sq౳΋ར༻ from http://twitter.github.io/finagle/ Twitter͕։ൃ

Slide 6

Slide 6 text

Future/Promise͕େ׆༂

Slide 7

Slide 7 text

ͦΜͳ͋Δ೔…

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

“Callbacks are imperative, promises are functional” from http://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity/

Slide 10

Slide 10 text

ஶऀ: James Coglan͞Μ • ΠΪϦεͷ Ruby/JavaScript ϓϩάϥϚ • Haskell΍ؔ਺ܕϓϩάϥϛϯάʹৄ͍͠ • FayeɺHeistɺJS.Classͷ࡞ऀ

Slide 11

Slide 11 text

هࣄͷཁ఺ • ”Node.js͸ίʔϧόοΫͰͳ͘ϓϩϛεΛ࠾ ༻͢Δ΂͖ͩͬͨ”ͱओுɻ • ϓϩϛεϞσϧ͕༏Ε͍ͯΔཧ༝Λɺ๛෋ͳ ۩ମྫΛݩʹղઆɻ • ͱͯ΋௕͍

Slide 12

Slide 12 text

௒͕Μ͹ͬͯಡഁ

Slide 13

Slide 13 text

㱺 ἤΒΕΔ

Slide 14

Slide 14 text

͏͓͒͒…ʢඞࢮʣ

Slide 15

Slide 15 text

΋͏ɺΰʔϧͯ͠΋͍͍ΑͶ…ʁ from https://gist.github.com/okapies/5354929

Slide 16

Slide 16 text

Oh...

Slide 17

Slide 17 text

ຊ೔͸͓ট͖͍͖ͨͩ ͋Γ͕ͱ͏͍͟͝·͢ m( _ _ )m

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

ඇಉظϓϩάϥϛϯά

Slide 20

Slide 20 text

ඇಉظॲཧΛॻ࣌͘ʹ ԿΛߟ͑Δʁ A. λεΫಉ࢜ͷґଘؔ܎Λߟ͑Δɻ B. ඞཁͳૢ࡞ͷॱংΛߟ͑Δɻ C.BΛ࣮ݱ͢Δ੍ޚϑϩʔΛॻ͘ɻ

Slide 21

Slide 21 text

ίʔϧόοΫ vs. ϓϩϛε ※Ҏ߱ͷίʔυྫ͸جຊతʹ ”Promises are functional...” ΑΓҾ༻ɻ

Slide 22

Slide 22 text

// fs.readFile(filename, callback) fs.readFile('file1.txt', // ͠͹Β͕࣌ؒ͘ܦͭͱ... function(error, buffer) { // ݁Ռ͕ඈͼग़ͯ͠ݱΕΔ } }; ίʔϧόοΫ

Slide 23

Slide 23 text

ίʔϧόοΫͷྑ͘ͳ͍ͱ͜Ζ • ॲཧΛϞδϡʔϧԽͨ͠Γ૊ΈཱͯͨΓ ͢Δͷ͕೉͍͠ɻ • ஞ࣍ॲཧ͔ฒྻॲཧ͔Λ໌ࣔతʹ੍ޚ͢ Δඞཁ͕͋Δɻ

Slide 24

Slide 24 text

”ωετ஍ࠈ (Pyramid of Doom)”͸ຊ࣭Ͱ͸ͳ͍ step1(function (value1) { step2(value1, function(value2) { step3(value2, function(value3) { step4(value3, function(value4) { // ... }); }); }); });

Slide 25

Slide 25 text

Slide 26

Slide 26 text

ྫ: ෳ਺ͷϑΝΠϧΛฒྻతʹ fs.stat ͯ͠ mtime ΛऔΓग़͢ɻ file1 file2 file3 stat mtime stat stat mtime mtime ฒྻॲཧ શͯͷ݁Ռ͕ ἧͬͨΒ࣍΁

Slide 27

Slide 27 text

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!

Slide 28

Slide 28 text

ผͷॲཧΛ ෇͚଍͍ͨ͠…

Slide 29

Slide 29 text

file1 ͷ size Λ࢖͏ॲཧΛ௥Ճ͢Δɻ file1 file2 file3 stat mtime stat stat mtime mtime size

Slide 30

Slide 30 text

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 ΛऔΓग़͢ॲཧΛ௥Ճ

Slide 31

Slide 31 text

ਖ਼͍͠ॱংͰɺ͔ͭޮ཰ྑ͘ॲཧͰ͖Δ ίʔυΛॻ͖͍ͨɻ file1 file2 file3 stat mtime stat stat mtime mtime size ֤ϑΝΠϧ͸Ұ౓͚ͩΞΫηε͢Δ file1 ͕औಘͰ͖ͨΒશͯͷstat ͕ἧͬͯͳͯ͘΋ॲཧ͢Δ

Slide 32

Slide 32 text

੍໿৚݅Λ͖ͪΜͱ ຬͨ͢ίʔυΛ ॻ͘ͱ͜͏ͳΔ

Slide 33

Slide 33 text

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...

Slide 34

Slide 34 text

• ॲཧΛϞδϡʔϧԽͨ͠Γ૊ΈཱͯͨΓ͢Δͷ͕೉͍͠ɻ • ஞ࣍ॲཧ͔ฒྻॲཧ͔Λ໌ࣔతʹ੍ޚ͢Δඞཁ͕͋Δɻ • ਖ਼͘͠ಈ͘ίʔυΛॻ͘ͷ͕େมɻ • ઃܭͷҙਤ͕໌֬Ͱͳ͘ϝϯςφϯεੑ͕௿͍ɻ • ॲཧͷ࣮ߦઓུʢஞ͔࣍ฒྻ͔ʣ࣍ୈͰɺޙଓͷλεΫΛ ௥Ճ͢Δํ๏͕มΘͬͯ͠·͏ɻ

Slide 35

Slide 35 text

ίʔϧόοΫ vs. ϓϩϛε

Slide 36

Slide 36 text

ϓϩϛεͱ͸ • ”׬ྃͯ͠ͳ͍͔΋͠Εͳ͍ܭࢉ”ͷ݁ Ռ͕ೖͬͯΔശɻ • ϓϩϛεࣗମ΋஋ͳͷͰɺؔ਺ͷؒͰ ड͚౉͠Ͱ͖Δɻ • ܭࢉ͕׬ྃ͢ΔͱಛఆͷॲཧΛݺͼग़ ͯ͘͠ΕΔػೳΛ࣋ͭ৔߹͕ଟ͍ɻ

Slide 37

Slide 37 text

var p1 = new Promise(); p1.then(console.log); ... p1.resolve(42); ϓϩϛε͕ղܾ͞Εͨ࣌ ʹݺͿؔ਺Λొ࿥ ϓϩϛεΛղܾ͢Δ 㱺 ͜͜Ͱ͸ console ʹ “42” ͕ग़ྗ͞ΕΔ

Slide 38

Slide 38 text

ͱ͜ΖͰ…

Slide 39

Slide 39 text

ͱ͍͏λΠτϧͰ͕͢ ͢΂ͯͷϓϩϛε͕ ؔ਺ܕͳΘ͚Ͱ͸͋Γ·ͤΜ

Slide 40

Slide 40 text

ݴޠ΍ϥΠϒϥϦʹΑͬͯେ͖͘ػೳ͕ҧ͏ • Πϕϯτ௨஌ػೳ͕͋Δ͔ • ߹੒Ͱ͖Δ͔ • ಡΈࠐΈઐ༻දݱ͕͋Δ͔ • ΤϥʔϋϯυϦϯάͰ͖Δ͔ ໊લ΋༷ʑ: • Future • Promise • Deferred • I-var • …

Slide 41

Slide 41 text

ϓϩϛε × ؔ਺ܕ

Slide 42

Slide 42 text

ؔ਺ܕͬͯͳ͋ʹʁ

Slide 43

Slide 43 text

ؔ਺ܕϓϩάϥϛϯά ͋ΒΏΔ΋ͷΛ஋ͱͯ͠ ѻ͏͜ͱͰ໰୊Λղ͘ख๏ ʹ ”ࣜࢦ޲”ͱ΋ݺ͹ΕΔ

Slide 44

Slide 44 text

໋ྩܕϓϩάϥϛϯά • Ͳ͏΍Δ͔ (how) Λɺ໋ྩγʔέϯεΛ໌ࣔతʹهड़ ͯ͠Ϛγϯʹ఻͑Δɻ ؔ਺ܕϓϩάϥϛϯά • ԿΛͯ͠΄͍͔͠ (what) Λ”஋ಉ࢜ͷؔ܎”ʹΑͬͯه ड़͠Ϛγϯʹ఻͑Δɻ • ίϯϐϡʔλ͸”஋ಉ࢜ͷؔ܎”͔Β໋ྩγʔέϯεΛ ܭࢉ͢Δɻ

Slide 45

Slide 45 text

ؔ਺ ஋ಉ࢜ͷґଘؔ܎Λ දݱ͢Δಓ۩ ʹ

Slide 46

Slide 46 text

function func(in) { return /* in ͔Β out Λܭࢉ */; } out = func(in) ”out ͸ in ʹґଘ͍ͯ͠Δ”ͱಡΊΔ ؔ਺ ஋Λೖྗͯ͠ɺม׵ͯ͠ɺ஋Λग़ྗ͢Δ ग़ྗ͸ೖྗʹʢͷΈʣґଘ͢Δ ʹ

Slide 47

Slide 47 text

ෳ਺ͷؔ਺Λ߹੒ͯ͠ ΑΓେ͖ͳؔ਺Λ࡞Δ

Slide 48

Slide 48 text

ؔ਺ͷग़ྗΛ ผͷؔ਺ͷೖྗ΁ͱܨ͛ͯ ॲཧͷύΠϓϥΠϯΛ࡞Δ function f(in) { return /* in ͔Β out Λܭࢉ */ } function g(in) { return /* in ͔Β out Λܭࢉ */ } out = g(f(in)) f ͷग़ྗΛ g ʹೖྗ͢Δ ಉ༷ʹ”out ͸ in ʹґଘ͍ͯ͠Δ”ͱಡΊΔ

Slide 49

Slide 49 text

ؔ਺ܕϓϩάϥϛϯά •͋ΒΏΔ΋ͷΛ”஋”ͱͯ͠ѻ͏ɻ •஋ಉ࢜ͷґଘؔ܎Λ”ؔ਺”Ͱදݱ͢Δɻ •ෳ਺ͷؔ਺Λ߹੒ͯ͠ΑΓେ͖ͳؔ਺Λ࡞Δɻ ʹ

Slide 50

Slide 50 text

ϓϩϛε × ؔ਺ܕ •͋ΒΏΔϓϩϛεΛ”஋”ͱͯ͠ѻ͏ɻ •ϓϩϛεಉ࢜ͷґଘؔ܎Λ”ؔ਺”Ͱදݱ͢Δɻ •ෳ਺ͷඇಉظܭࢉΛ߹੒ͯ͠ΑΓେ͖ͳඇಉظܭ ࢉΛ࡞Δɻ ʹ

Slide 51

Slide 51 text

ϓϩϛεΛ࢖ͬͯΈΔ

Slide 52

Slide 52 text

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 ͷ഑ྻ͔Βϓϩϛεͷ഑ྻΛ࡞Δ

Slide 53

Slide 53 text

// 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; }; } ίʔϧόοΫ൛͔Βϓϩϛε൛Λ࡞Δϔϧύʔؔ਺

Slide 54

Slide 54 text

ผͷॲཧΛ ෇͚Ճ͍͑ͨ࣌͸ʁ

Slide 55

Slide 55 text

var statsPromises = paths.map(fs_stat); statsPromises[0].then(function(stat) { /* stat.size */ }); then() Λ࢖͏ͱϓϩϛεʹґଘ͢Δ ผͷඇಉظॲཧΛهड़Ͱ͖Δ file1 stat size ϓϩϛεΛ࡞Δ fs_stat then(function(stat)->...) ശ͔Β஋ΛऔΓग़͠ ؔ਺ʹ༩͑Δ

Slide 56

Slide 56 text

then() ͸ඇಉظܭࢉͷ݁ՌΛλΠϛϯάඇ ґଘͰѻ͑Δɻthen() ʹ౉͞ΕΔؔ਺͸ɺ • ஋͕͍ͭར༻ՄೳʹͳΔ͔ • λεΫΛͲΜͳॱ൪Ͱॲཧ͢Δ͔ Λؾʹ͢Δඞཁ͕ͳ͍ɻ

Slide 57

Slide 57 text

ϓϩϛεͱ then() Λ࢖͏ͱ… • ίϯϐϡʔλ͸ɺهड़͞Εͨґଘؔ܎Λ ݩʹ࣮ߦॱংΛࣗಈతʹܾఆ͢Δɻ • ख࡞ۀͰ੍ޚϑϩʔΛॻ͘ඞཁ͕ͳ͍ʂ

Slide 58

Slide 58 text

Ϧετʹର͢Δ ϓϩϛε

Slide 59

Slide 59 text

શͯͷ stat ͕ἧ͔ͬͯΒॲཧ͍ͨ͠… file1 file2 file3 stat mtime stat stat mtime mtime ݁Ռ͕ἧ͏ͷΛ଴͍ͪͨ

Slide 60

Slide 60 text

stat mtime stat stat mtime mtime ”ϓϩϛεͷϦετ”Λ ”Ϧετʹର͢Δϓϩϛεʹ”ม׵ stat stat stat var statsPromises = paths.map(fs_stat); list(statsPromises).then(function(stats) { /* stats */ }); ଴ͪ߹Θ͕ͤՄೳʹʂ list() then()

Slide 61

Slide 61 text

// 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() Λ௥Ճ͢Δϔϧύʔؔ਺

Slide 62

Slide 62 text

·ͱΊΔͱ…

Slide 63

Slide 63 text

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 ґଘؔ܎ͷهड़ͷΈͰ ஞ࣍ॲཧ΋ฒྻॲཧ΋࣮ݱͰ͖͍ͯΔʂ

Slide 64

Slide 64 text

A. λεΫಉ࢜ͷґଘؔ܎Λߟ͑Δɻ B. ඞཁͳૢ࡞ͷॱংΛߟ͑Δɻ C.BΛ࣮ݱ͢Δ੍ޚϑϩʔΛॻ͘ɻ ϓϩϛεΛ࢖͏ͱɺίϯϐϡʔλ͕ A ͔Β࠷దͳ C Λಋग़ͯ͘͠ΕΔʂ

Slide 65

Slide 65 text

ϓϩϛε͸೉͍͠ʁ

Slide 66

Slide 66 text

Mikeal Rogersࢯͷ൓࿦ • ”ϓϩϛεΛ࢖ͬͨ API ͸ɺͦΕ͕Ͳ͏ ಈ࡞͢Δ͔Λௐ΂Δඞཁ͕͋Δɻ” • ”then() ΍ list() ͸ҙຯ࿦ΛӅṭ͢Δͷ Ͱɺೝ஌తෛՙ͕େ͖͍ɻ” from http://www.futurealoof.com/posts/broken-promises.html

Slide 67

Slide 67 text

James Coglanࢯͷ࠶൓࿦ • ”ϓϩϛε͕ easy Ͱ͋Δ͔͸ॏཁͰͳ ͍ɻsimple Ͱ͋Δ͔Λ໰͏΂͖ɻ” • ”΍Γ͍ͨ͜ͱ͕มΘͬͨ࣌ʹίʔυͷ มߋ͕গͳ͘ࡁΉɻϓϩϛε͸ɺίϨ Ϋγϣϯ΍ඇಉظੑ΍࣮ߦॱংͱ͍ͬ ͨ֓೦ͱ෼཭Ͱ͖Δ͔Βͩɻ” from http://blog.jcoglan.com/2013/04/01/callbacks-promises-and-simplicity/

Slide 68

Slide 68 text

ʢࢲͷҙݟʣ • ”ίετͷࢧ෷͍Λੵۃతʹ༛༧ͭͭ͠ ίʔσΟϯάͰ͖Δ”͜ͱ͸ϓϩτλΠ ϐϯά౳Ͱ΋ॏཁͳੑ࣭ɻ • ίετͱϝϦοτΛఱṝʹ͔͚Δɻ • ͨͩɺඇಉظϓϩάϥϛϯάͷ”ίετ ͷࢧ෷͍ظݶ”͸ҙ֎ͱૣ͍ͷͰ͸ʁ

Slide 69

Slide 69 text

͓࿩Ͱ͖ͳ͔ͬͨࣄ • Ϧετॲཧ (reduce) ͱͷ૊Έ߹Θͤ • ஗ԆϓϩϛεʹΑΔґଘੑղܾ • Promises/A+ ͱϞφυ • Fantasy Land ͔Β Real World ΁

Slide 70

Slide 70 text

• ίʔϧόοΫ͸࣮ߦॱংΛ໌ࣔ͢Δͷ Ͱͱ͖ͬͭ΍͍͢ɻ • มߋʹڧ͘ɺϞδϡϥʔͳϓϩάϥϜ Λॻ͖͍ͨͳΒϓϩϛε͕͓קΊɻ • ੍ޚϑϩʔ͸ػցʹߟ͑ͤ͞Α͏ʂ ·ͱΊ

Slide 71

Slide 71 text

ϝοηʔδ • ؔ਺ܕɺษڧͯ͠Έ·ͤΜ͔ʁ • ྫ͑࢓ࣄͰ࢖Θͳͯ͘΋ɺϓϩάϥϚ ͱͯܳ͠෩Λ޿͛Δͷʹେ͍ʹ໾ཱͭ ͱࢥ͍·͢ɻ

Slide 72

Slide 72 text

ࢁຊ࿨඙, ”ؔ਺ϓϩάϥϛϯά͕ڭ͑ͯ͘ΕΔن཯” ؾܰʹֶΜͰΈ͍ͨਓ޲͚:

Slide 73

Slide 73 text

Miran Lipovaa, “͍͢͝Haskellͨͷֶ͘͠΅͏!”ʢΦʔϜࣾʣ ΨνͰ΍Γ͍ͨਓ޲͚: