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
50k
Distributed System and Functional Programming
okapies
1
610
Reactive とは何か? #reactive_shinjuku
okapies
43
12k
Play and Reactive Streams (English version)
okapies
0
280
Play and Reactive Streams #play_ja
okapies
9
1k
Reactive Streams 入門 #jjug
okapies
58
19k
Finagle 最新事情 #kwkni_scala
okapies
4
400
Scala for Java Programmers (Short Edition)
okapies
9
3k
Other Decks in Programming
See All in Programming
Vue3の一歩踏み込んだパフォーマンスチューニング2024
hal_spidernight
3
3.1k
Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的なCSRF対策 / kaigionrails-2024-csrf
corocn
5
3.4k
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
210
gopls を改造したら開発生産性が高まった
satorunooshie
8
240
2万ページのSSG運用における工夫と注意点 / Vue Fes Japan 2024
chinen
3
1.3k
Importmapを使ったJavaScriptの 読み込みとブラウザアドオンの影響
swamp09
4
1.2k
Server Driven Compose With Firebase
skydoves
0
400
Dev ContainersとGitHub Codespacesの素敵な関係
ymd65536
1
130
offers_20241022_imakiire.pdf
imakurusu
2
360
CPython 인터프리터 구조 파헤치기 - PyCon Korea 24
kennethanceyer
0
240
OpenTelemetryでRailsのパフォーマンス分析を始めてみよう(KoR2024)
ymtdzzz
4
1.5k
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
1
230
Featured
See All Featured
Docker and Python
trallard
40
3.1k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
250
21k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
43
6.6k
Build The Right Thing And Hit Your Dates
maggiecrowley
32
2.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
27
790
A designer walks into a library…
pauljervisheath
202
24k
KATA
mclloyd
29
13k
Gamification - CAS2011
davidbonilla
80
5k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
664
120k
Speed Design
sergeychernyshev
24
570
Building Your Own Lightsaber
phodgson
102
6k
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ͨͷֶ͘͠΅͏!”ʢΦʔϜࣾʣ ΨνͰΓ͍ͨਓ͚: