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.6k
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
52k
Distributed System and Functional Programming
okapies
1
630
Reactive とは何か? #reactive_shinjuku
okapies
43
12k
Play and Reactive Streams (English version)
okapies
0
290
Play and Reactive Streams #play_ja
okapies
9
1.1k
Reactive Streams 入門 #jjug
okapies
58
19k
Finagle 最新事情 #kwkni_scala
okapies
4
420
Scala for Java Programmers (Short Edition)
okapies
9
3.1k
Other Decks in Programming
See All in Programming
SRE、開発、QAが協業して挑んだリリースプロセス改革@SRE Kaigi 2025
nealle
3
4.3k
Domain-Driven Transformation
hschwentner
2
1.9k
Compose でデザインと実装の差異を減らすための取り組み
oidy
1
310
プログラミング言語学習のススメ / why-do-i-learn-programming-language
yashi8484
0
130
Honoとフロントエンドの 型安全性について
yodaka
7
1.1k
Spring gRPC について / About Spring gRPC
mackey0225
0
220
お前もAI鬼にならないか?👹Bolt & Cursor & Supabase & Vercelで人間をやめるぞ、ジョジョー!👺
taishiyade
6
4k
dbt Pythonモデルで実現するSnowflake活用術
trsnium
0
120
CI改善もDatadogとともに
taumu
0
110
『GO』アプリ データ基盤のログ収集システムコスト削減
mot_techtalk
0
120
Introduction to kotlinx.rpc
arawn
0
690
自分ひとりから始められる生産性向上の取り組み #でぃーぷらすオオサカ
irof
8
2.8k
Featured
See All Featured
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
2.1k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.2k
Making the Leap to Tech Lead
cromwellryan
133
9.1k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
410
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
29
1k
Rails Girls Zürich Keynote
gr2m
94
13k
Raft: Consensus for Rubyists
vanstee
137
6.8k
A Philosophy of Restraint
colly
203
16k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.2k
The Cult of Friendly URLs
andyhume
78
6.2k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.8k
Bash Introduction
62gerente
611
210k
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ͨͷֶ͘͠΅͏!”ʢΦʔϜࣾʣ ΨνͰΓ͍ͨਓ͚: