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
430
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
290
軽量デバッグツールPostmortemの紹介.pdf
athos
1
190
Clojure 1.10 概要紹介
athos
3
610
やってみる!clojure.spec
athos
4
980
Clojure 1.9 概要紹介
athos
4
1.4k
ここ最近のClojureScript
athos
5
1.7k
(= ? (+ nREPL Docker))
athos
0
500
clojure.specの話
athos
3
2.2k
clojure.specの話(仮)
athos
2
340
Other Decks in Programming
See All in Programming
DevFest - Serverless 101 with Google Cloud Functions
tunmise
0
140
ある日突然あなたが管理しているサーバーにDDoSが来たらどうなるでしょう?知ってるようで何も知らなかったDDoS攻撃と対策 #phpcon.2024
akase244
2
7.7k
テストコードのガイドライン 〜作成から運用まで〜
riku929hr
7
1.4k
Fibonacci Function Gallery - Part 2
philipschwarz
PRO
0
210
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
1.4k
[JAWS-UG横浜 #80] うわっ…今年のServerless アップデート、少なすぎ…?
maroon1st
0
100
盆栽転じて家具となる / Bonsai and Furnitures
aereal
0
1.9k
React 19でお手軽にCSS-in-JSを自作する
yukukotani
5
570
Package Traits
ikesyo
1
210
Внедряем бюджетирование, или Как сделать хорошо?
lamodatech
0
940
ChatGPT とつくる PHP で OS 実装
memory1994
PRO
3
190
混沌とした例外処理とエラー監視に秩序をもたらす
morihirok
13
2.3k
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
6
500
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
7k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
570
KATA
mclloyd
29
14k
The Cost Of JavaScript in 2023
addyosmani
46
7.2k
4 Signs Your Business is Dying
shpigford
182
22k
Bash Introduction
62gerente
610
210k
The Pragmatic Product Professional
lauravandoore
32
6.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.2k
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ͷνϟωϧͱγʔϜϨεʹ࿈ܞͰ͖Δੑ