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
1.1k
Clojure 1.9 概要紹介
athos
4
1.5k
ここ最近のClojureScript
athos
5
1.7k
(= ? (+ nREPL Docker))
athos
0
550
clojure.specの話
athos
3
2.3k
clojure.specの話(仮)
athos
2
360
Other Decks in Programming
See All in Programming
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
110
OSS開発者の憂鬱
yusukebe
12
5.8k
Flutterアプリ運用の現場で役立った監視Tips 5選
ostk0069
1
500
Web エンジニアが JavaScript で AI Agent を作る / JSConf JP 2025 sponsor session
izumin5210
4
2k
乱雑なコードの整理から学ぶ設計の初歩
masuda220
PRO
32
14k
例外処理を理解して、設計段階からエラーを見つけやすく、起こりにくく #phpconfuk
kajitack
12
6.4k
How Software Deployment tools have changed in the past 20 years
geshan
0
4.2k
Building AI with AI
inesmontani
PRO
1
260
アーキテクチャと考える迷子にならない開発者テスト
irof
9
3.3k
モデル駆動設計をやってみよう Modeling Forum2025ワークショップ/Let’s Try Model-Driven Design
haru860
0
180
予防に勝る防御なし(2025年版) - 堅牢なコードを導く様々な設計のヒント / Growing Reliable Code PHP Conference Fukuoka 2025
twada
PRO
39
13k
CloudflareのSandbox SDKを試してみた
syumai
0
180
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
11
940
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.2k
A better future with KSS
kneath
239
18k
Writing Fast Ruby
sferik
630
62k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.7k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
192
56k
jQuery: Nuts, Bolts and Bling
dougneiner
65
8k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
31
2.7k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Unsuck your backbone
ammeep
671
58k
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ͷνϟωϧͱγʔϜϨεʹ࿈ܞͰ͖Δੑ