Promise.resolve(42)
.then(val => console.log(val));
Promise 是在 JavaScript 中處理非同步操作的常見方式。您可以在 ClojureScript 中透過呼叫 promise 方法輕鬆地使用它們。
JavaScript
Promise.resolve(42)
.then(val => console.log(val));
ClojureScript
(.then (js/Promise.resolve 42)
#(js/console.log %))
然而,在 ClojureScript 中鏈式 promise 方法會導致程式碼階梯式地堆疊。使用 thread-first 巨集,我們可以恢復更優雅的程式碼。
JavaScript
Promise.resolve(42)
.then(val => console.log(val))
.catch(err => console.log(err))
.finally(() => console.log('cleanup'));
ClojureScript
(.finally
(.catch
(.then (js/Promise.resolve 42)
#(js/console.log %))
#(js/console.log %))
#(js/console.log "cleanup"))
; same as above
(-> (js/Promise.resolve 42)
(.then #(js/console.log %))
(.catch #(js/console.log %))
(.finally #(js/console.log "cleanup")))
大量使用 await
的 Promise 程式碼會導致更複雜且不友善的程式碼結構。參考 Puppeteer 用法中的這個範例。
JavaScript
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
} catch (err) {
console.log(err);
}
await browser.close();
})();
ClojureScript
(def puppeteer (js/require "puppeteer"))
(-> (.launch puppeteer)
(.then (fn [browser]
(-> (.newPage browser)
(.then (fn [page]
(-> (.goto page "https://clojure.dev.org.tw")
(.then #(.screenshot page #js{:path "screenshot.png"}))
(.catch #(js/console.log %))
(.then #(.close browser)))))))))
為了馴服這類型的程式碼,我們轉向使用 core.async
。
ClojureScript 在 core.async 中提供了出色的非同步程式設計工具。其中一個特別方便的工具是 <p!
巨集,它會在 go
區塊內使用 promise。
使用 go
區塊可以讓我們編寫看起來是同步的程式碼,即使它實際上是非同步的,這就像 JavaScript 中的 await
和 async
所做的那樣。
ClojureScript
(:require
[cljs.core.async :refer [go]]
[cljs.core.async.interop :refer-macros [<p!]])
(def puppeteer (js/require "puppeteer"))
(go
(let [browser (<p! (.launch puppeteer))
page (<p! (.newPage browser))]
(try
(<p! (.goto page "https://clojure.dev.org.tw"))
(<p! (.screenshot page #js{:path "screenshot.png"}))
(catch js/Error err (js/console.log (ex-cause err))))
(.close browser)))
這只是冰山一角。core.async
為您提供了非常強大的、類似佇列的通道,其功能遠遠不止處理一次性的 promise。
原始作者:Filipe Silva