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
CSC307 Lecture 03
javiergs
PRO
1
450
C-Shared Buildで突破するAI Agent バックテストの壁
po3rin
0
430
AI時代を生き抜く 新卒エンジニアの生きる道
coconala_engineer
1
500
Java 25, Nuevas características
czelabueno
0
130
QAフローを最適化し、品質水準を満たしながらリリースまでの期間を最短化する #RSGT2026
shibayu36
0
510
안드로이드 9년차 개발자, 프론트엔드 주니어로 커리어 리셋하기
maryang
1
150
AIによるイベントストーミング図からのコード生成 / AI-powered code generation from Event Storming diagrams
nrslib
1
170
公共交通オープンデータ × モバイルUX 複雑な運行情報を 『直感』に変換する技術
tinykitten
PRO
0
180
Deno Tunnel を使ってみた話
kamekyame
0
300
AI 駆動開発ライフサイクル(AI-DLC):ソフトウェアエンジニアリングの再構築 / AI-DLC Introduction
kanamasa
11
4.8k
ThorVG Viewer In VS Code
nors
0
500
Claude Codeの「Compacting Conversation」を体感50%減! CLAUDE.md + 8 Skills で挑むコンテキスト管理術
kmurahama
1
700
Featured
See All Featured
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
54
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
0
110
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
34
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.1k
For a Future-Friendly Web
brad_frost
180
10k
Chasing Engaging Ingredients in Design
codingconduct
0
93
It's Worth the Effort
3n
187
29k
My Coaching Mixtape
mlcsv
0
20
Deep Space Network (abreviated)
tonyrice
0
32
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
74
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
140
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ͨͷֶ͘͠΅͏!”ʢΦʔϜࣾʣ ΨνͰΓ͍ͨਓ͚: