Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Node, Promises and Functional Programming
Search
Yuta Okamoto
April 25, 2013
Programming
11
1.7k
Node, Promises and Functional Programming
東京Node学園 8時限目 ”Nodeとプロミスと、時々、関数型” by @okapies
http://connpass.com/event/2125/
Yuta Okamoto
April 25, 2013
Tweet
Share
More Decks by Yuta Okamoto
See All by Yuta Okamoto
NFTとは何ではないか
okapies
64
120k
#Ergodox とケーブルの話
okapies
5
54k
Distributed System and Functional Programming
okapies
1
670
Reactive とは何か? #reactive_shinjuku
okapies
43
13k
Play and Reactive Streams (English version)
okapies
0
310
Play and Reactive Streams #play_ja
okapies
9
1.1k
Reactive Streams 入門 #jjug
okapies
58
19k
Finagle 最新事情 #kwkni_scala
okapies
4
460
Scala for Java Programmers (Short Edition)
okapies
9
3.1k
Other Decks in Programming
See All in Programming
機能追加とリーダー業務の類似性
rinchoku
2
1.3k
Swift Updates - Learn Languages 2025
koher
2
470
Zendeskのチケットを Amazon Bedrockで 解析した
ryokosuge
3
300
テストカバレッジ100%を10年続けて得られた学びと品質
mottyzzz
2
590
Kiroの仕様駆動開発から見えてきたAIコーディングとの正しい付き合い方
clshinji
1
210
Testing Trophyは叫ばない
toms74209200
0
860
AWS発のAIエディタKiroを使ってみた
iriikeita
1
180
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
360
プロポーザル駆動学習 / Proposal-Driven Learning
mackey0225
2
1.3k
print("Hello, World")
eddie
2
530
知っているようで知らない"rails new"の世界 / The World of "rails new" You Think You Know but Don't
luccafort
PRO
1
110
Improving my own Ruby thereafter
sisshiki1969
1
160
Featured
See All Featured
Building a Modern Day E-commerce SEO Strategy
aleyda
43
7.6k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
Building an army of robots
kneath
306
46k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.1k
Code Review Best Practice
trishagee
70
19k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.5k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
31
2.2k
Facilitating Awesome Meetings
lara
55
6.5k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
Agile that works and the tools we love
rasmusluckow
330
21k
How to Think Like a Performance Engineer
csswizardry
26
1.9k
Transcript
Nodeͱϓϩϛεͱ ࣌ʑɺؔܕ @okapies
୭ʁ • Ԭຊ ༤ଠ (@okapies) • Java/Scala ϓϩάϥϚ • ؔܕϓϩάϥϛϯάमߦத…
• ٕज़จॻͷ༁Λ͍͔ͭͬͯ͘·͢ • Effective Scala (http://twitter.github.io/effectivescala/ index-ja.html) • “Scala Conference in Japan 2013” ༁νʔϜ
ܦҢ
Java VMͷ ੩తܕ͖ݴޠ ΦϒδΣΫτࢦʴؔܕ
ඇಉظRPCϥΠϒϥϦ”Finagle” Scala ͷ Node.jsʂ Tumblr, 4sqར༻ from http://twitter.github.io/finagle/ Twitter͕։ൃ
Future/Promise͕େ׆༂
ͦΜͳ͋Δ…
None
“Callbacks are imperative, promises are functional” from http://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity/
ஶऀ: James Coglan͞Μ • ΠΪϦεͷ Ruby/JavaScript ϓϩάϥϚ • Haskellؔܕϓϩάϥϛϯάʹৄ͍͠ •
FayeɺHeistɺJS.Classͷ࡞ऀ
هࣄͷཁ • ”Node.jsίʔϧόοΫͰͳ͘ϓϩϛεΛ࠾ ༻͢Δ͖ͩͬͨ”ͱओுɻ • ϓϩϛεϞσϧ͕༏Ε͍ͯΔཧ༝Λɺ๛ͳ ۩ମྫΛݩʹղઆɻ • ͱ͍ͯ
͕Μͬͯಡഁ
㱺 ἤΒΕΔ
͏͓͒͒…ʢඞࢮʣ
͏ɺΰʔϧ͍͍ͯ͠ΑͶ…ʁ from https://gist.github.com/okapies/5354929
Oh...
ຊ͓ট͖͍͖ͨͩ ͋Γ͕ͱ͏͍͟͝·͢ m( _ _ )m
None
ඇಉظϓϩάϥϛϯά
ඇಉظॲཧΛॻ࣌͘ʹ ԿΛߟ͑Δʁ A. λεΫಉ࢜ͷґଘؔΛߟ͑Δɻ B. ඞཁͳૢ࡞ͷॱংΛߟ͑Δɻ C.BΛ࣮ݱ͢Δ੍ޚϑϩʔΛॻ͘ɻ
ίʔϧόοΫ vs. ϓϩϛε ※Ҏ߱ͷίʔυྫجຊతʹ ”Promises are functional...” ΑΓҾ༻ɻ
// fs.readFile(filename, callback) fs.readFile('file1.txt', // ͠Β͕࣌ؒ͘ܦͭͱ... function(error, buffer) { //
݁Ռ͕ඈͼग़ͯ͠ݱΕΔ } }; ίʔϧόοΫ
ίʔϧόοΫͷྑ͘ͳ͍ͱ͜Ζ • ॲཧΛϞδϡʔϧԽͨ͠ΓΈཱͯͨΓ ͢Δͷ͕͍͠ɻ • ஞ࣍ॲཧ͔ฒྻॲཧ͔Λ໌ࣔతʹ੍ޚ͢ Δඞཁ͕͋Δɻ
”ωετࠈ (Pyramid of Doom)”ຊ࣭Ͱͳ͍ step1(function (value1) { step2(value1, function(value2) {
step3(value2, function(value3) { step4(value3, function(value4) { // ... }); }); }); });
ྫ
ྫ: ෳͷϑΝΠϧΛฒྻతʹ fs.stat ͯ͠ mtime ΛऔΓग़͢ɻ file1 file2 file3 stat
mtime stat stat mtime mtime ฒྻॲཧ શͯͷ݁Ռ͕ ἧͬͨΒ࣍
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!
ผͷॲཧΛ ͚͍ͨ͠…
file1 ͷ size Λ͏ॲཧΛՃ͢Δɻ file1 file2 file3 stat mtime stat
stat mtime mtime size
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 ΛऔΓग़͢ॲཧΛՃ
ਖ਼͍͠ॱংͰɺ͔ͭޮྑ͘ॲཧͰ͖Δ ίʔυΛॻ͖͍ͨɻ file1 file2 file3 stat mtime stat stat mtime
mtime size ֤ϑΝΠϧҰ͚ͩΞΫηε͢Δ file1 ͕औಘͰ͖ͨΒશͯͷstat ͕ἧͬͯͳͯ͘ॲཧ͢Δ
੍݅Λ͖ͪΜͱ ຬͨ͢ίʔυΛ ॻ͘ͱ͜͏ͳΔ
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...
• ॲཧΛϞδϡʔϧԽͨ͠ΓΈཱͯͨΓ͢Δͷ͕͍͠ɻ • ஞ࣍ॲཧ͔ฒྻॲཧ͔Λ໌ࣔతʹ੍ޚ͢Δඞཁ͕͋Δɻ • ਖ਼͘͠ಈ͘ίʔυΛॻ͘ͷ͕େมɻ • ઃܭͷҙਤ͕໌֬Ͱͳ͘ϝϯςφϯεੑ͕͍ɻ • ॲཧͷ࣮ߦઓུʢஞ͔࣍ฒྻ͔ʣ࣍ୈͰɺޙଓͷλεΫΛ
Ճ͢Δํ๏͕มΘͬͯ͠·͏ɻ
ίʔϧόοΫ vs. ϓϩϛε
ϓϩϛεͱ • ”ྃͯ͠ͳ͍͔͠Εͳ͍ܭࢉ”ͷ݁ Ռ͕ೖͬͯΔശɻ • ϓϩϛεࣗମͳͷͰɺؔͷؒͰ ड͚͠Ͱ͖Δɻ • ܭࢉ͕ྃ͢ΔͱಛఆͷॲཧΛݺͼग़ ͯ͘͠ΕΔػೳΛ࣋ͭ߹͕ଟ͍ɻ
var p1 = new Promise(); p1.then(console.log); ... p1.resolve(42); ϓϩϛε͕ղܾ͞Εͨ࣌ ʹݺͿؔΛొ
ϓϩϛεΛղܾ͢Δ 㱺 ͜͜Ͱ console ʹ “42” ͕ग़ྗ͞ΕΔ
ͱ͜ΖͰ…
ͱ͍͏λΠτϧͰ͕͢ ͯ͢ͷϓϩϛε͕ ؔܕͳΘ͚Ͱ͋Γ·ͤΜ
ݴޠϥΠϒϥϦʹΑͬͯେ͖͘ػೳ͕ҧ͏ • Πϕϯτ௨ػೳ͕͋Δ͔ • ߹Ͱ͖Δ͔ • ಡΈࠐΈઐ༻දݱ͕͋Δ͔ • ΤϥʔϋϯυϦϯάͰ͖Δ͔ ໊લ༷ʑ:
• Future • Promise • Deferred • I-var • …
ϓϩϛε × ؔܕ
ؔܕͬͯͳ͋ʹʁ
ؔܕϓϩάϥϛϯά ͋ΒΏΔͷΛͱͯ͠ ѻ͏͜ͱͰΛղ͘ख๏ ʹ ”ࣜࢦ”ͱݺΕΔ
໋ྩܕϓϩάϥϛϯά • Ͳ͏Δ͔ (how) Λɺ໋ྩγʔέϯεΛ໌ࣔతʹهड़ ͯ͠Ϛγϯʹ͑Δɻ ؔܕϓϩάϥϛϯά • ԿΛͯ͠΄͍͔͠ (what)
Λ”ಉ࢜ͷؔ”ʹΑͬͯه ड़͠Ϛγϯʹ͑Δɻ • ίϯϐϡʔλ”ಉ࢜ͷؔ”͔Β໋ྩγʔέϯεΛ ܭࢉ͢Δɻ
ؔ ಉ࢜ͷґଘؔΛ දݱ͢Δಓ۩ ʹ
function func(in) { return /* in ͔Β out Λܭࢉ */;
} out = func(in) ”out in ʹґଘ͍ͯ͠Δ”ͱಡΊΔ ؔ Λೖྗͯ͠ɺมͯ͠ɺΛग़ྗ͢Δ ग़ྗೖྗʹʢͷΈʣґଘ͢Δ ʹ
ෳͷؔΛ߹ͯ͠ ΑΓେ͖ͳؔΛ࡞Δ
ؔͷग़ྗΛ ผͷؔͷೖྗͱܨ͛ͯ ॲཧͷύΠϓϥΠϯΛ࡞Δ function f(in) { return /* in ͔Β
out Λܭࢉ */ } function g(in) { return /* in ͔Β out Λܭࢉ */ } out = g(f(in)) f ͷग़ྗΛ g ʹೖྗ͢Δ ಉ༷ʹ”out in ʹґଘ͍ͯ͠Δ”ͱಡΊΔ
ؔܕϓϩάϥϛϯά •͋ΒΏΔͷΛ””ͱͯ͠ѻ͏ɻ •ಉ࢜ͷґଘؔΛ”ؔ”Ͱදݱ͢Δɻ •ෳͷؔΛ߹ͯ͠ΑΓେ͖ͳؔΛ࡞Δɻ ʹ
ϓϩϛε × ؔܕ •͋ΒΏΔϓϩϛεΛ””ͱͯ͠ѻ͏ɻ •ϓϩϛεಉ࢜ͷґଘؔΛ”ؔ”Ͱදݱ͢Δɻ •ෳͷඇಉظܭࢉΛ߹ͯ͠ΑΓେ͖ͳඇಉظܭ ࢉΛ࡞Δɻ ʹ
ϓϩϛεΛͬͯΈΔ
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 ͷྻ͔ΒϓϩϛεͷྻΛ࡞Δ
// 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; }; } ίʔϧόοΫ൛͔Βϓϩϛε൛Λ࡞Δϔϧύʔؔ
ผͷॲཧΛ ͚Ճ͍͑ͨ࣌ʁ
var statsPromises = paths.map(fs_stat); statsPromises[0].then(function(stat) { /* stat.size */ });
then() Λ͏ͱϓϩϛεʹґଘ͢Δ ผͷඇಉظॲཧΛهड़Ͱ͖Δ file1 stat size ϓϩϛεΛ࡞Δ fs_stat then(function(stat)->...) ശ͔ΒΛऔΓग़͠ ؔʹ༩͑Δ
then() ඇಉظܭࢉͷ݁ՌΛλΠϛϯάඇ ґଘͰѻ͑Δɻthen() ʹ͞ΕΔؔɺ • ͕͍ͭར༻ՄೳʹͳΔ͔ • λεΫΛͲΜͳॱ൪Ͱॲཧ͢Δ͔ Λؾʹ͢Δඞཁ͕ͳ͍ɻ
ϓϩϛεͱ then() Λ͏ͱ… • ίϯϐϡʔλɺهड़͞ΕͨґଘؔΛ ݩʹ࣮ߦॱংΛࣗಈతʹܾఆ͢Δɻ • ख࡞ۀͰ੍ޚϑϩʔΛॻ͘ඞཁ͕ͳ͍ʂ
Ϧετʹର͢Δ ϓϩϛε
શͯͷ stat ͕ἧ͔ͬͯΒॲཧ͍ͨ͠… file1 file2 file3 stat mtime stat stat
mtime mtime ݁Ռ͕ἧ͏ͷΛ͍ͪͨ
stat mtime stat stat mtime mtime ”ϓϩϛεͷϦετ”Λ ”Ϧετʹର͢Δϓϩϛεʹ”ม stat stat
stat var statsPromises = paths.map(fs_stat); list(statsPromises).then(function(stats) { /* stats */ }); ͪ߹Θ͕ͤՄೳʹʂ list() then()
// 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() ΛՃ͢Δϔϧύʔؔ
·ͱΊΔͱ…
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 ґଘؔͷهड़ͷΈͰ ஞ࣍ॲཧฒྻॲཧ࣮ݱͰ͖͍ͯΔʂ
A. λεΫಉ࢜ͷґଘؔΛߟ͑Δɻ B. ඞཁͳૢ࡞ͷॱংΛߟ͑Δɻ C.BΛ࣮ݱ͢Δ੍ޚϑϩʔΛॻ͘ɻ ϓϩϛεΛ͏ͱɺίϯϐϡʔλ͕ A ͔Β࠷దͳ C Λಋग़ͯ͘͠ΕΔʂ
ϓϩϛε͍͠ʁ
Mikeal Rogersࢯͷ • ”ϓϩϛεΛͬͨ API ɺͦΕ͕Ͳ͏ ಈ࡞͢Δ͔ΛௐΔඞཁ͕͋Δɻ” • ”then()
list() ҙຯΛӅṭ͢Δͷ Ͱɺೝతෛՙ͕େ͖͍ɻ” from http://www.futurealoof.com/posts/broken-promises.html
James Coglanࢯͷ࠶ • ”ϓϩϛε͕ easy Ͱ͋Δ͔ॏཁͰͳ ͍ɻsimple Ͱ͋Δ͔Λ͏͖ɻ” • ”Γ͍ͨ͜ͱ͕มΘͬͨ࣌ʹίʔυͷ
มߋ͕গͳ͘ࡁΉɻϓϩϛεɺίϨ Ϋγϣϯඇಉظੑ࣮ߦॱংͱ͍ͬ ͨ֓೦ͱͰ͖Δ͔Βͩɻ” from http://blog.jcoglan.com/2013/04/01/callbacks-promises-and-simplicity/
ʢࢲͷҙݟʣ • ”ίετͷࢧ͍Λੵۃతʹ༛༧ͭͭ͠ ίʔσΟϯάͰ͖Δ”͜ͱϓϩτλΠ ϐϯάͰॏཁͳੑ࣭ɻ • ίετͱϝϦοτΛఱṝʹ͔͚Δɻ • ͨͩɺඇಉظϓϩάϥϛϯάͷ”ίετ ͷࢧ͍ظݶ”ҙ֎ͱૣ͍ͷͰʁ
͓Ͱ͖ͳ͔ͬͨࣄ • Ϧετॲཧ (reduce) ͱͷΈ߹Θͤ • ԆϓϩϛεʹΑΔґଘੑղܾ • Promises/A+ ͱϞφυ
• Fantasy Land ͔Β Real World
• ίʔϧόοΫ࣮ߦॱংΛ໌ࣔ͢Δͷ Ͱͱ͖͍ͬͭ͢ɻ • มߋʹڧ͘ɺϞδϡϥʔͳϓϩάϥϜ Λॻ͖͍ͨͳΒϓϩϛε͕͓קΊɻ • ੍ޚϑϩʔػցʹߟ͑ͤ͞Α͏ʂ ·ͱΊ
ϝοηʔδ • ؔܕɺษڧͯ͠Έ·ͤΜ͔ʁ • ྫ͑ࣄͰΘͳͯ͘ɺϓϩάϥϚ ͱͯܳ͠෩Λ͛Δͷʹେ͍ʹཱͭ ͱࢥ͍·͢ɻ
ࢁຊ, ”ؔϓϩάϥϛϯά͕ڭ͑ͯ͘ΕΔن” ؾܰʹֶΜͰΈ͍ͨਓ͚:
Miran Lipovaa, “͍͢͝Haskellͨͷֶ͘͠΅͏!”ʢΦʔϜࣾʣ ΨνͰΓ͍ͨਓ͚: