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
500
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
370
軽量デバッグツールPostmortemの紹介.pdf
athos
1
200
Clojure 1.10 概要紹介
athos
3
670
やってみる!clojure.spec
athos
4
1.1k
Clojure 1.9 概要紹介
athos
4
1.5k
ここ最近のClojureScript
athos
5
1.8k
(= ? (+ nREPL Docker))
athos
0
560
clojure.specの話
athos
3
2.3k
clojure.specの話(仮)
athos
2
360
Other Decks in Programming
See All in Programming
Unicodeどうしてる? PHPから見たUnicode対応と他言語での対応についてのお伺い
youkidearitai
PRO
0
170
AIエージェントの設計で注意するべきポイント6選
har1101
6
2.9k
実はマルチモーダルだった。ブラウザの組み込みAI🧠でWebの未来を感じてみよう #jsfes #gemini
n0bisuke2
3
1.4k
안드로이드 9년차 개발자, 프론트엔드 주니어로 커리어 리셋하기
maryang
1
150
PostgreSQLで手軽にDuckDBを使う!DuckDB&pg_duckdb入門/osc25hi-duckdb
takahashiikki
0
230
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
8
2.2k
re:Invent 2025 トレンドからみる製品開発への AI Agent 活用
yoskoh
0
570
ELYZA_Findy AI Engineering Summit登壇資料_AIコーディング時代に「ちゃんと」やること_toB LLMプロダクト開発舞台裏_20251216
elyza
2
920
20251212 AI 時代的 Legacy Code 營救術 2025 WebConf
mouson
0
240
AtCoder Conference 2025「LLM時代のAHC」
imjk
2
640
AIで開発はどれくらい加速したのか?AIエージェントによるコード生成を、現場の評価と研究開発の評価の両面からdeep diveしてみる
daisuketakeda
1
220
公共交通オープンデータ × モバイルUX 複雑な運行情報を 『直感』に変換する技術
tinykitten
PRO
0
180
Featured
See All Featured
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.3k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
34k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.3k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
エンジニアに許された特別な時間の終わり
watany
106
220k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
The agentic SEO stack - context over prompts
schlessera
0
580
Odyssey Design
rkendrick25
PRO
0
450
Large-scale JavaScript Application Architecture
addyosmani
515
110k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
54
48k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
180
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ͷνϟωϧͱγʔϜϨεʹ࿈ܞͰ͖Δੑ