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
680
Reactive とは何か? #reactive_shinjuku
okapies
43
13k
Play and Reactive Streams (English version)
okapies
0
330
Play and Reactive Streams #play_ja
okapies
9
1.1k
Reactive Streams 入門 #jjug
okapies
58
20k
Finagle 最新事情 #kwkni_scala
okapies
4
480
Scala for Java Programmers (Short Edition)
okapies
9
3.2k
Other Decks in Programming
See All in Programming
Graviton と Nitro と私
maroon1st
0
150
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
4
1k
Navigating Dependency Injection with Metro
l2hyunwoo
1
200
Basic Architectures
denyspoltorak
0
140
Deno Tunnel を使ってみた話
kamekyame
0
280
gunshi
kazupon
1
130
Rubyで鍛える仕組み化プロヂュース力
muryoimpl
0
230
PostgreSQLで手軽にDuckDBを使う!DuckDB&pg_duckdb入門/osc25hi-duckdb
takahashiikki
0
210
AI時代を生き抜く 新卒エンジニアの生きる道
coconala_engineer
1
480
DevFest Android in Korea 2025 - 개발자 커뮤니티를 통해 얻는 가치
wisemuji
0
180
Tinkerbellから学ぶ、Podで DHCPをリッスンする手法
tomokon
0
150
クラウドに依存しないS3を使った開発術
simesaba80
0
190
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.2k
Being A Developer After 40
akosma
91
590k
Context Engineering - Making Every Token Count
addyosmani
9
570
Faster Mobile Websites
deanohume
310
31k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.6k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.4k
Prompt Engineering for Job Search
mfonobong
0
130
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Odyssey Design
rkendrick25
PRO
0
450
For a Future-Friendly Web
brad_frost
180
10k
Are puppies a ranking factor?
jonoalderson
0
2.5k
Building the Perfect Custom Keyboard
takai
1
670
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ͨͷֶ͘͠΅͏!”ʢΦʔϜࣾʣ ΨνͰΓ͍ͨਓ͚: