ClojureScript

Promise の相互運用

JavaScript の Promise を直接使用する

Promise は JavaScript で非同期操作を処理するための一般的な方法です。Promise メソッドを呼び出すことで、ClojureScript でも簡単に使用できます。

JavaScript

Promise.resolve(42)
  .then(val => console.log(val));

ClojureScript

(.then (js/Promise.resolve 42)
       #(js/console.log %))

ただし、ClojureScript で Promise メソッドをチェーンすると、コードがカスケードされます。スレッドファーストマクロを使用すると、よりエレガントなコードに戻ることができます。

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.dokyumento.jp")
                              (.then #(.screenshot page #js{:path "screenshot.png"}))
                              (.catch #(js/console.log %))
                              (.then #(.close browser)))))))))

このようなコードを制御するために、core.asyncに目を向けます。

core.async と Promise を使用する

ClojureScript には、core.asyncという優れた非同期プログラミング機能が用意されています。特に便利なツールの 1 つである<p!マクロは、goブロック内で Promise を消費します。

goブロックを使用すると、JavaScript でawaitasyncが実際の非同期操作でも同期操作のように見えるコードを書くことができます。

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.dokyumento.jp"))
      (<p! (.screenshot page #js{:path "screenshot.png"}))
      (catch js/Error err (js/console.log (ex-cause err))))
    (.close browser)))

これはほんの序の口です。core.asyncには、単一の Promise を処理する以上の機能を持つ非常に強力なキューのようなチャネルがあります。

リポジトリ理論コードウォークスルーブログ記事core-asyncについて詳しく読むことができます。

元の作者: Filipe Silva