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
kitchen-async: a promising (?) Promise library,...
Search
OHTA Shogo
January 29, 2018
Programming
3
490
kitchen-async: a promising (?) Promise library, or a poor man's core.async
2018/01/29のLisp meetup #60の発表資料です。
OHTA Shogo
January 29, 2018
Tweet
Share
More Decks by OHTA Shogo
See All by OHTA Shogo
テンクーでのClojure活用事例
athos
0
360
軽量デバッグツールPostmortemの紹介.pdf
athos
1
200
Clojure 1.10 概要紹介
athos
3
660
やってみる!clojure.spec
athos
4
1k
Clojure 1.9 概要紹介
athos
4
1.5k
ここ最近のClojureScript
athos
5
1.7k
(= ? (+ nREPL Docker))
athos
0
540
clojure.specの話
athos
3
2.3k
clojure.specの話(仮)
athos
2
360
Other Decks in Programming
See All in Programming
CSC509 Lecture 10
javiergs
PRO
0
170
AI駆動開発カンファレンスAutumn2025 _AI駆動開発にはAI駆動品質保証
autifyhq
0
150
業務でAIを使いたい話
hnw
0
260
Flutterアプリ運用の現場で役立った監視Tips 5選
ostk0069
1
350
FlutterKaigi 2025 システム裏側
yumnumm
0
760
Snowflake リリースに注意を払いたくなる話
masaaya
0
100
Functional Calisthenics in Kotlin: Kotlinで「関数型エクササイズ」を実践しよう
lagenorhynque
0
120
高単価案件で働くための心構え
nullnull
0
120
仕様がそのままテストになる!Javaで始める振る舞い駆動開発
ohmori_yusuke
5
2.7k
AIエージェントでのJava開発がはかどるMCPをAIを使って開発してみた / java mcp for jjug
kishida
4
380
AI駆動開発ライフサイクル(AI-DLC)のホワイトペーパーを解説
swxhariu5
0
540
Rails Girls Sapporo 2ndの裏側―準備の日々から見えた、私が得たもの / SAPPORO ENGINEER BASE #11
lemonade_37
2
110
Featured
See All Featured
RailsConf 2023
tenderlove
30
1.3k
The Pragmatic Product Professional
lauravandoore
36
7k
Designing for humans not robots
tammielis
254
26k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.5k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.7k
YesSQL, Process and Tooling at Scale
rocio
174
15k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.2k
[RailsConf 2023] Rails as a piece of cake
palkan
57
6k
Scaling GitHub
holman
463
140k
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
11
920
How to train your dragon (web standard)
notwaldorf
97
6.4k
Transcript
LJUDIFOBTZODBQSPNJTJOH 1SPNJTFMJCSBSZ PSBQPPSNBO`TDPSFBTZOD -JTQNFFUVQ !BUIPT
ࣗݾհ ‣ 5XJUUFS!BUIPT ‣ (JU)VCBUIPT ‣ $MPKVSF 4DSJQU ॻ͍ͯ·͢
3FBDU/BUJWFΞϓϦΛ$MPKVSF4DSJQUͰ "MFYB4LJMMΛ$MPKVSF4DSJQUͰ
5-%3 ‣ $MPKVSF$MPKVSF4DSJQUͰඇಉظϓϩάϥϛϯάͱ͍͏ͱ DPSFBTZOD͕༗໊͕ͩৗʹ࠷ྑͷબࢶͱݶΒͳ͍ ‣ +BWB4DSJQU &$."4DSJQU 1SPNJTFBTZODBXBJU Λݴޠ༷ʹऔΓೖΕ͍ͯͯɺ+4ͱͷJOUFSPQΛߟ͑Δͱ 1SPNJTFΛʮ͏·͘ʯѻ͑Δ͜ͱඞཁ
‣ 1SPNJTFͱDPSFBTZODͱ͏·͍ͬͯͨ͘͘Ίͷϥ ΠϒϥϦLJUDIFOBTZODΛ࡞ͬͨɺͱ͍͏
ࠓ͢͜ͱ ‣ എܠ +BWB4DSJQUք۾ͷඇಉظϓϩάϥϛϯάࣄ $MPKVSF4DSJQUք۾ͷඇಉظϓϩάϥϛϯάࣄ ‣ $MPKVSF4DSJQUͰͷඇಉظϓϩάϥϯάͷ ‣
LJUDIFOBTZODͷհ
എܠ
+BWB4DSJQUք۾ͷඇಉظࣄ ‣ +BWB4DSJQUͷଟ͘ͷॲཧܥγϯάϧεϨου ‣ *0ॲཧͷྃΛಉظతʹͪ߹Θͤͯ͠·͏ͱɺͦͷ εϨουॲཧྃ·ͰԿͰ͖ͳ͘ͳΔ ‣ *0ͷྃͪͷؒεϨουΛଞͷॲཧʹ໌͚͢͜ͱ ͰεϨουΛޮతʹ͑ΔΑ͏ʹͳΔ ˠඇಉظϓϩάϥϛϯά
ίʔϧόοΫ ‣ ॲཧ͕ྃͨ͠ޙʹ࣮ߦ͢ΔॲཧΛ͢ ‣ +BWB4DSJQUͱͯͬ͠ͱݪ࢝తͳඇಉظ"1*ͷ࡞Γํ ‣ ඇಉظॲཧ͕ଟஈʹͳΔͱίʔϧόοΫ͕ωετͯ͠ίʔυͷ Մಡੑ͕ѱ͘ͳΔ ͍ΘΏΔʮίʔϧόοΫࠈʯ const
fs = require(‘fs’) fs.readFile(‘input.txt’, (err, data) => { console.log(data) })
1SPNJTF ‣ 1SPNJTFඇಉظͳܭࢉ݁ՌΛอ࣋͢Δσʔλܕ ‣ ίʔϧόοΫΛҾʹड͚ΔΘΓʹ1SPNJTFΛฦ͢Α͏ ʹ͓ͯ͘͠ͱʜ const readFileAsync = (path)
=> { return new Promise((resolve, reject) => { fs.readFile(path, (err, data) => { if (err) return reject(err) resolve(data) }) }) }
1SPNJTF ‣ ॲཧͷྃޙʹ࣮ߦ͢ΔॲཧΛޙ͔ΒઃఆͰ͖Δ ‣ ϝιουνΣʔϯͰଟஈͷॲཧΛܨ͛ΒΕΔ readFileAsync(‘input.txt’) .then((text) => { return
JSON.parse(text) }) .then((json) => { console.log(json) }) .catch((err) => { console.log(err) })
BTZODBXBJU ‣ 1SPNJTFΛͬͨॲཧΛܗࣜͰ͔͋ͨಉظతͳॲཧͷΑ͏ʹ هड़Ͱ͖Δ ‣ ଟ͘ͷ߹1SPNJTFΛ͏ΑΓ੍ޚϑϩʔ͕͔Γ͘͢ͳΔ (async () => {
try { const text = await readFileAsync(‘input.txt’) return JSON.parse(text) } catch (err) { console.log(err) } })()
+BWB4DSJQUք۾ͷඇಉظࣄ ‣ &$."4DSJQU &4 ͷ༷ͷऔΓࠐΈ &41SPNJTF &4BTZODBXBJU ‣
8FCඪ४ͷ"1*Ͱͷར༻ 'FUDI"1* 8FC35$ͷϝσΟΞऔಘ 4FSWJDF8PSLFS FUDFUD ‣ αʔυύʔςΟͷOQNϞδϡʔϧͰͷར༻ +BWB4DSJQUͷ༷ʑͳ"1*ʹ1SPNJTF͕ΘΕͭͭ͋Δ
$MPKVSF4DSJQUք۾ͷඇಉظࣄ ‣ ΄΅DPSFBTZODҰͳงғؾ ‣ DPSFBTZOD$41 ڠௐεϨουͱνϟωϧΛհͨ͠ϝο ηʔδύογϯά ΛϞσϧʹ͍ͯ͠Δ ‣ 1SPNJTFͱಉ༷ͷ͍ํͰ͖Δ͕ɺͭͷνϟωϧ͔Β
ෳճΛड͚औͬͨΓɺΛૹΓฦͤΔΑΓڧྗ
DPSFBTZODͰͷඇಉظॲཧ (require ‘[clojure.core.async :as a]) (defn read-file [path] (let [ch
(a/chan)] (fs.readFile path (fn [err data] (a/put! ch (or err data)))) ch)) (a/go (let [data (a/<! (read-file “input.txt”))] (js/console.log data)))
ར༻ऀ͔Βͷ͓Έ ʮ$MPKVSF4DSJQU͔Βͩͱ1SPNJTFΛѻ͏ίʔυ Λ͖ͬ͢Γॻ͚·ͤΜʯ உੑձࣾһ ˞͜ΕݸਓͷײͰײ͡ํʹݸਓ͕ࠩ͋Γ·͢
ར༻ऀ͔Βͷ͓Έ ʮ$MPKVSF4DSJQU͔Βͩͱ1SPNJTFΛѻ͏ίʔυ Λ͖ͬ͢Γॻ͚·ͤΜʯ உੑձࣾһ (-> (readFileAsync “input.txt”) (.then (fn [text]
(js/JSON.parse text))) (.then (fn [json] (js/console.log json))) (.catch (fn [err] (js/console.log err)))) ˞͜ΕݸਓͷײͰײ͡ํʹݸਓ͕ࠩ͋Γ·͢
ར༻ऀ͔Βͷ͓Έ ʮ$MPKVSF4DSJQU͔Βͩͱ1SPNJTFΛѻ͏ίʔυ Λ͖ͬ͢Γॻ͚·ͤΜʯ உੑձࣾһ (-> (puppeteer/launch) (.then (fn [browser] (->
(.newPage browser) (.then (fn [page] (.then (.goto page “https://www.google.com") #(.screenshot page #js{:path “image.png"})))) (.then #(.close browser))))))) ˞͜ΕݸਓͷײͰײ͡ํʹݸਓ͕ࠩ͋Γ·͢
ར༻ऀ͔Βͷ͓Έ ‣ ͦͦ1SPNJTF+4Ͱॻ͖͍͢Α͏ʹઃܭ͞Ε͍ͯΔ ‣ ෳࡶͳ߹ͩͱ݁ہ1SPNJTFΛωετͤͯ͞͏ඞཁ͕͋Δ ‣ BTZODBXBJU͘Β͍͖ͬ͢ΓͱඇಉظͳίʔυΛॻ͖͍ͨ ʮ$MPKVSF4DSJQU͔Βͩͱ1SPNJTFΛѻ͏ίʔυ Λ͖ͬ͢Γॻ͚·ͤΜʯ உੑձࣾһ
˞͜ΕݸਓͷײͰײ͡ํʹݸਓ͕ࠩ͋Γ·͢
ར༻ऀ͔Βͷ͓Έ ‣ 1SPNJTFϔϏʔͳ"1*Λ͏ͱ͖ʹνϟωϧʹมͨ͘͠ͳ͍ ‣ HPϒϩοΫेʹෳࡶͳϚΫϩ ల։ܗσΧ͍ XFC"1*Λճୟͨ͘Ί͚ͩʹHPϒϩοΫΛॻ͖ͨ͘ͳ͍ ‣
DPSFBTZODΤϥʔॲཧ͕͏·͘ͳ͍ ‣ TFMGIPTUFE$-+4 -VNP1MBODL Ͱͦͷ··Ͱಈ͔ͳ͍ ʮDPSFBTZOD͔ͨ͠ʹڧྗͳಓ۩ͳΜ͚ͩͲɺ ͬ͘͠Γ͜ͳ͍߹͋Γ·͢ΑͶʯ உੑձࣾһ ˞͜ΕݸਓͷײͰײ͡ํʹݸਓ͕ࠩ͋Γ·͢
ސ٬͕ຊʹඞཁͩͬͨͷ ‣ ʮෳͷඇಉظॲཧΛஞ࣍తʹ࣮ߦ͢Δʯͱ͍͏తͷͨΊʹ DPSFBTZODΦʔόʔΩϧ ‣ ඇಉظϓϩάϥϛϯάͷதఔʹෳࡶͳίʔυΛॻ͘ͷʹదͨ͠ ಓ۩͕΄͍͠ ͷෳࡶ͞ ίʔϧόοΫ Promise
core.async
ސ٬͕ຊʹඞཁͩͬͨͷ ‣ ʮෳͷඇಉظॲཧΛஞ࣍తʹ࣮ߦ͢Δʯͱ͍͏తͷͨΊʹ DPSFBTZODΦʔόʔΩϧ ‣ ඇಉظϓϩάϥϛϯάͷதఔʹෳࡶͳίʔυΛॻ͘ͷʹదͨ͠ ಓ۩͕΄͍͠ ͷෳࡶ͞ ίʔϧόοΫ Promise
core.async
ސ٬͕ຊʹඞཁͩͬͨͷ ‣ ʮෳͷඇಉظॲཧΛஞ࣍తʹ࣮ߦ͢Δʯͱ͍͏తͷͨΊʹ DPSFBTZODΦʔόʔΩϧ ‣ ඇಉظϓϩάϥϛϯάͷதఔʹෳࡶͳίʔυΛॻ͘ͷʹదͨ͠ ಓ۩͕΄͍͠ ‣ ႩఆόαϛͰνΣʔϯιʔͰͳ͍מΓࠐΈόαϛ͕΄͍͠ʂ ͷෳࡶ͞
ίʔϧόοΫ Promise core.async
LJUDIFOBTZOD
LJUDIFOBTZOD ‣ 1SPNJTFΛத৺ͱͯ͠ɺ$MPKVSF4DSJQUͰඇಉظͳίʔυ Λॻ͖͘͢͢ΔϥΠϒϥϦ $MPKVSFͷΠσΟΦϜతͳॻ͖ํͰ1SPNJTFΛѻ͑Δߏจ DPSFBTZODͷνϟωϧͱγʔϜϨεʹ࿈ܞͰ͖Δੑ ‣ ໊લlFWFSZUIJOHCVUUIFLJUDIFOTJOLz
ԿͰ͔ΜͰ Λͬͨ͡ͷ
LJUDIFOBTZOD͕ఏڙ͢Δ"1* ‣ 1SPNJTF༝དྷͷؔɾϚΫϩ QSPNJTFɾUIFOɾDBUDI BMMɾSBDF ‣ $MPKVSFͷߏจͰ1SPNJTFΛѻ͏ҥߏจ
QMFU εϨοσΟϯάϚΫϩ ϧʔϓ ྫ֎ॲཧ
QSPNJTFɾUIFOɾDBUDI ‣ +4ͷ1SPNJTFͱ ΄΅ Ձͳ"1*Λఏڙ͍ͯ͠Δ (require ‘[kitchen-async.promise :as p]) (->
(p/promise [resolve reject] (resolve 42)) (p/then (fn [x] (js/console.log x))) (p/catch* (fn [err] (js/console.log err))))
QMFUϚΫϩ (p/let [<var1> <init1> <var2> <init2> …] <body>) (p/then <init1>
(p/then (fn [<var1>] (p/then <init2> (fn [<var2>] … <body> …))))) ্ͷϑΥʔϜ͓͓ΉͶҎԼͷΑ͏ʹల։͞ΕΔ
QMFUϚΫϩ (p/let [browser (puppeteer/launch) page (.newPage browser)] (.goto page "https://www.example.com")
(.screenshot page #js{:path "image.png"}) (.close browser)) (-> (puppeteer/launch) (.then (fn [browser] (-> (.newPage browser) (.then (fn [page] (.then (.goto page “https://www.example.com”) #(.screenshot page #js{:path "image.png"})))) (.then #(.close browser))))))) ্ͷίʔυQMFUΛͬͯҎԼͷΑ͏ʹॻ͖͑ΒΕΔ
εϨοσΟϯάϚΫϩ (p/let [x (f) y (g x)] (h y)) (p/->
(f) g h) ্ͷίʔυQΛͬͯҎԼͷΑ͏ʹॻ͖͑ΒΕΔ w Q QTPNF QTPNFಉ༷ʹ͑Δ
ϧʔϓ ‣ QMPPQɾQSFDVSΛͬͯ௨ৗͱಉ༷ʹϧʔϓ͕ॻ͚Δ ‣ QSFDVSQMPPQͷதͰͷΈ༻Ͱ͖Δ (p/loop [i (p/timeout 1000 0)]
(when (<= i 10) (prn i) (p/recur (p/timeout 1000 (inc i)))))
ྫ֎ॲཧ ‣ QUSZɾQDBUDIɾQpOBMMZΛͬͯ௨ৗͱಉ༷ʹྫ֎ॲཧ͕ॻ͚Δ ‣ QDBUDIɾQpOBMMZQUSZͷதͰͷΈ༻Ͱ͖Δ (p/try (write-async fd content) (p/catch
:default e (js/console.log e)) (p/finally (close fd)))
DPSFBTZODͱͷ γʔϜϨεͳ࿈ܞ
QSPNJTF ‣ ҙͷΛ1SPNJTFʹม DPFSDJPO ͢Δؔ (defprotocol Promisable (->promise [this])) (extend-protocol
Promisable js/Promise (->promise [this] this) default (->promise [this] (p/promise [resolve] (resolve this)))
҉ͷQSPNJTF ‣ LJUDIFOBTZODͷͯ͢ͷ"1*҉ʹQSPNJTFΛద༻ ‣ 1SPNJTFҎ֎ͷ1SPNJTFͱ۠ผͳ͘͏͜ͱ͕Ͱ͖Δ (p/let [x (f), y (g
x)] (h y)) (p/then p f) (p/then (->promise p) f) (p/let [x (->promise (f)), y (->promise (g x))] (h y))
DPSFBTZODνϟωϧͱͷ࿈ܞ (ns kitchen-async.promise.from-channel (:require [clojure.core.async :as a] [clojure.core.async.impl.channels :refer [ManyToManyChannel]]
[kitchen-async.promise :as p])) (extend-protocol p/Promisable ManyToManyChannel (->promise [ch] (p/promise [resolve reject] (a/go (let [x (a/<! ch)] (if (instance? js/Error x) (reject x) (resolve x)))))))
DPSFBTZODνϟωϧͱͷ࿈ܞ ‣ dQSPNJTFGSPNDIBOOFMΛϩʔυ͢Ενϟωϧͱ 1SPNJTFΛγʔϜϨεʹ͑ΔΑ͏ʹͳΔ (require ‘kitchen-async.promise.from-channel) (def ch (a/chan)) (p/loop
[i 0, x ch] (prn x) (when (<= i 10) (p/recur (inc i) ch)))
࣮༻ྫ ‣ DPSFBTZODͱಉͷ͜ͱ͕HPϚΫϩΛΘͣʹͰ͖Δ ‣ ͨͩ͠ɺύϑΥʔϚϯεతʹDPSFBTZODͷํ͕͍͍ (defn debounce ([c ms] (debounce
(a/chan) c ms)) ([c' c ms] (p/loop [start nil loc c] (if (nil? start) (do (a/put! c' loc) (p/recur (js/Date.) nil)) (p/let [loc c] (if (>= (- (js/Date.) start) ms) (p/recur nil loc) (p/recur (js/Date.) loc))))) c'))
·ͱΊ ‣ $MPKVSF$MPKVSF4DSJQUͰඇಉظϓϩάϥϛϯάͱ͍͏ͱ DPSFBTZOD͕༗໊͕ͩৗʹ࠷ྑͷબࢶͱݶΒͳ͍ ‣ +BWB4DSJQU &$."4DSJQU 1SPNJTFBTZODBXBJU Λݴޠ༷ʹऔΓೖΕ͍ͯͯɺ+4ͱͷJOUFSPQΛߟ͑Δͱ 1SPNJTFΛʮ͏·͘ʯѻ͑Δ͜ͱඞཁ
‣ 1SPNJTFͱDPSFBTZODͱ͏·͍ͬͯͨ͘͘Ίͷϥ ΠϒϥϦLJUDIFOBTZODΛ࡞ͬͨɺͱ͍͏
LJUDIFOBTZOD ‣ 1SPNJTFΛத৺ͱͯ͠ɺ$MPKVSF4DSJQUͰඇಉظͳίʔυ Λॻ͖͘͢͢ΔϥΠϒϥϦ ‣ $MPKVSFͷΠσΟΦϜతͳॻ͖ํͰ1SPNJTFΛѻ͑Δߏจ ‣ DPSFBTZODͷνϟωϧͱγʔϜϨεʹ࿈ܞͰ͖Δੑ