# ClojureScript에 Async/Await 도입

> Clean Markdown view of GeekNews topic #29336. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=29336](https://news.hada.io/topic?id=29336)
- GeekNews Markdown: [https://news.hada.io/topic/29336.md](https://news.hada.io/topic/29336.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-05-10T06:33:24+09:00
- Updated: 2026-05-10T06:33:24+09:00
- Original source: [clojurescript.org](https://clojurescript.org/news/2026-05-07-release)
- Points: 1
- Comments: 1

## Topic Body

- **ClojureScript 1.12.145**는 `^:async` 힌트를 붙인 함수를 JavaScript `async function`으로 출력하도록 컴파일러가 변경됨
- `await`로 **Promise** 값을 기다리는 ClojureScript 함수를 작성할 수 있어 JavaScript 상호운용성이 개선됨
- 테스트에도 **`^:async`** 를 사용할 수 있으며, `await`로 비동기 함수 호출 결과 검증이 가능함
- 최근 Clojure 설문에서 **async functions** 지원이 JavaScript 상호운용성 관련 ClojureScript 개선 요구 중 가장 높은 비중을 차지함
- 최신 브라우저 API와 인기 라이브러리를 다루는 일반적인 경우 **추가 의존성**을 도입할 필요가 줄어들며, 전체 변경 목록은 [ClojureScript changelog의 1.12.145 항목](https://github.com/clojure/clojurescript/blob/master/changes.md#1.12.145)에서 확인 가능함

---

### `^:async`와 `await` 사용
- ClojureScript 1.12.145는 `^:async` 힌트를 붙인 함수를 [JavaScript async function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)으로 출력하도록 컴파일러가 변경됨
- ClojureScript가 [ECMAScript 2016](https://clojurescript.org/news/2025-11-24)을 대상으로 하게 되면서 JavaScript 상호운용성 개선 영역을 신중히 선택할 수 있게 됨
- `await`를 사용해 `Promise` 값을 기다리는 ClojureScript 함수 작성이 가능해짐
  ```clojure
  (refer-global :only '[Promise])
  
  (defn ^:async foo [n]
    (let [x (await (Promise/resolve 10))
          y (let [y (await (Promise/resolve 20))]
              (inc y))
          ;; not async
          f (fn [] 20)]
      (+ n x y (f))))
  ```
- 테스트에도 `^:async`를 사용할 수 있으며, `await`로 비동기 함수 호출 결과를 검증할 수 있음
  ```clojure
  (deftest ^:async defn-test
    (try
      (let [v (await (foo 10))]
        (is (= 61 v)))
      (let [v (await (apply foo [10]))]
        (is (= 61 v)))
      (catch :default _ (is false))))
  ```

### 배경과 변경 목록
- 최근 Clojure 설문에서 **async functions** 지원이 JavaScript 상호운용성 관련 ClojureScript 개선 요구 중 가장 높은 비중을 차지함
- 이번 개선으로 최신 브라우저 API와 인기 라이브러리를 다루는 일반적인 경우 추가 의존성을 도입할 필요가 줄어듦
- 전체 수정, 변경, 개선 목록은 [ClojureScript changelog의 1.12.145 항목](https://github.com/clojure/clojurescript/blob/master/changes.md#1.12.145)에서 확인 가능함
- ClojureScript 1.12.145에는 커뮤니티 구성원 **Michiel Borkent**가 기여함

## Comments



### Comment 57134

- Author: neo
- Created: 2026-05-10T06:33:24+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=48059662) 
- borkdude가 이 스레드를 올렸고, 이번 릴리스의 기여자로도 올라와 있는 걸 봤음  
  오래전부터 **async/await 지원** 반대 논리는 대체로 두 가지였음: CLJS 컴파일러 전반에 깊은 변경이 필요하다는 점과, Promesa 같은 라이브러리의 매크로가 비슷한 편의성을 제공한다는 점  
  그 외에도 core.async를 쓰면 된다거나, 표현식 지향 언어는 async/await와 잘 맞지 않는다는 주장도 있었지만, 포럼에서 반복되던 주류 논거라기보다는 개인별 견해에 가까웠음  
  Clojurians Slack에서 borkdude는 지원 추가가 비현실적이라고 확신하지 않는다고 한 적이 있는데, 결국 시간을 들여 구현해낸 듯해서 정말 고마움
  - Borkdude가 먼저 자신의 ClojureScript 대체 구현인 **Squint**에 async/await를 구현해서 가능성을 보였고, 그때 얻은 내용을 핵심 CLJS 컴파일러로 가져온 것 같음

- 재미있는 사실은 ClojureScript가 JavaScript 자체에 async/await가 들어오기 훨씬 전부터 **core.async** 라이브러리로 비동기 패러다임을 지원했다는 것임  
  이 릴리스의 가치를 깎아내리려는 건 전혀 아니고, 의존성에 라이브러리 하나를 추가하는 것만으로 호스트 언어에 아직 없는 새 언어 기능을 쓸 수 있다는 점이 멋지다는 얘기임. Clojure는 굉장함
  - 확실히 그랬음. 많이 써봤고 동작도 잘했으며, 약간의 특이점은 있었지만 10년 넘게 사실상 async/await를 가지고 있었음  
    David Nolen의 발표를 보고 알게 된 것 같음  
    이후에는 프런트엔드에서 JavaScript를 최소한으로 쓰는 쪽으로 옮겼고, **SSE**는 단방향이라서 그 점이 아름다움. 요즘 여러 언어권 개발자들이 SSE에 관심을 갖는 걸 보니 반가움  
    David Nolen의 최근 발표 “A ClojureScript Survival Kit”도 좋았음: [https://youtu.be/BeE00vGC36E](<https://youtu.be/BeE00vGC36E>)  
    David “Swannodette” Nolen이 ClojureScript와 core.async 초창기부터 해온 작업에는 아무리 감사해도 부족함. 이 발표에서 특히 놀라운 건, 그가 ClojureScript를 버리고 서버 쪽의 순수 Clojure와 서버 전송 이벤트, 아주 약간의 JavaScript만 쓰는 방향에도 실제로 기대감을 보인다는 점임  
    실제 데모는 26:30쯤 시작함. 클라이언트에서 돌아가는 웹앱의 리소스 사용량을 보여준 뒤, 같은 웹앱을 서버에서 실행하고 SSE로 클라이언트에 단방향으로 밀어주는 모습을 보여주는데, 리소스 사용량이 거의 0에 가까워져서 꽤 강렬함  
    모든 경우에 맞지는 않겠지만, 최소한의 DOM 변형 라이브러리를 쓰니 웹앱과 상태를 추론하기가 더 쉬워졌음. 예전에는 Clojure용 REPL과 ClojureScript용 REPL을 둘 다 띄우고, 양방향 트래픽과 재현하기 어려운 상태를 많이 다뤄야 했는데, 지금은 훨씬 빠르고 재현도 쉬움
  - 맞지만 2026년에 **core.async를 피할 이유**도 많음  
    JavaScript 산출물이 커지고, 내재된 오류 모델이 없으며, 문제가 생기면 읽고 디버깅하기 어려운 상태 기계 코드로 변환됨  
    게다가 `go` 매크로는 자기 S-표현식 바깥의 코드를 변환할 수 없어서 함수가 지나치게 커지도록 유도함  
    어떤 Cognitect 사람이 말했듯이 “core.async는 아름다운 헛소리”임

- 최근 갑자기 소셜에서 **Clojure/ClojureScript**가 더 자주 보이는 게 의외임  
  2012년쯤 몇 년간 업무에서 썼지만, 다른 많은 사람들처럼 JVM을 떠나 타입 있는 함수형 언어로 옮겼음  
  요즘 관심이 늘어난 건 에이전트형 코딩 때문일까? 타입 검사도 없고 잘못된 문법 오류나 예약어도 적어서 코드 훑기가 더 빠른 걸까? S-표현식의 부활이 오는 건가 싶음
  - 개인적으로는 타입 있는 함수형 언어에서 ClojureScript로, 그리고 약 10년 전 Clojure로 옮겼음  
    내가 아는 진지한 Clojure 코드베이스들은 테스트 스위트에 많이 투자하므로, AI에게 테스트 스위트를 가장 효과적으로 쓰는 방법을 알려주는 기술만 추가하면 꽤 잘 달리게 할 수 있음  
    동료 중에는 에이전트가 **REPL**과 상호작용하게 하는 사람들도 있고, 매번 시작 비용을 내지 않으니 더 빠르다고 함. 나는 게을러서 거기까지는 안 했지만 지금도 충분히 빠름  
    Clojure는 걸리적거리는 요소가 적음. `false`와 `nil`을 제외하면 모두 참이고, 연산자 우선순위 표가 없으며, 핵심 언어가 불변·영속 자료구조를 기본으로 지원함  
    모든 것이 표현식이고, 연산자와 표현식이 뒤섞인 구조가 아님. `map`, `reduce`, `filter`는 내장되어 있고 일반 코드에서 당연히 쓰임  
    10년 전에 쓴 Clojure 코드는 오늘도 대체로 동작할 가능성이 높고, 생태계와 언어 설계자들은 코드를 깨뜨리는 일을 금기처럼 다룸  
    써본 언어 중 아이디어를 표현하는 데 가장 자유롭고 두통이 가장 적었음. 사실상의 역방향 디버거인 **Flowstorm**도 프로그래밍의 꿈 같은 도구임  
    만족스럽게 지내고 싶다면 참 좋은 언어임. 반대로 사용자 대부분이 그걸 당연하게 여겨서 많이 떠들지 않는 편임  
    상업적으로 Clojure를 쓰는 프로그래머 중에는 언어를 잘 이해하지 못해 그다지 행복하지 않은 사람도 많음. 본인이 원해서 선택한 게 아니거나 아직 준비가 안 된 경우가 많고, Clojure를 쓰기 전 다른 언어에서 싫었던 점들을 10년쯤 겪어봤어야 했다고 봄  
    Clojure 창시자 Rich Hickey의 소프트웨어 관련 영상들이 유명하고 영향력 있긴 하지만, 동료들이 그걸 봤거나 신경 쓴다는 뜻은 아님
  - 최근 관심 증가는 **Clojure 다큐멘터리** 공개 영향이 큰 것 같음: [https://clojure.org/about/documentary](<https://clojure.org/about/documentary>)
  - 에이전트형 코딩과 잘 맞는 또 다른 기능은 **REPL 주도 개발**임. 이론적으로 지원 가능한 다른 언어들에서 왜 이 접근이 더 널리 퍼지지 않았는지 모르겠음
  - 여러 언어에서 에이전트형 코딩을 해봤는데, **타입 있는 언어**가 훨씬 잘 맞음. 에이전트가 환각으로 만든 오류를 타입 시스템이 사실상 교정해주기 때문이고, 특히 큰 리팩터링에서 그렇음  
    큰 규모의 타입 없는 Python 코드베이스를 AI와 다루는 건 힘들었음. 테스트로 덮이지 않은 부분은 망가지지 않았는지 확인하는 작업이 너무 지루함  
    타입 시스템이 강할수록 더 좋음. 또한 AI 모델은 코드로 학습되므로 언어가 더 대중적일수록 성능도 더 좋을 가능성이 큼. ClojureScript는 좋지만 주류 언어는 아니라서 JavaScript보다 AI 성능이 떨어질 거라고 봄  
    결국 AI를 염두에 둔다면 타입 있는 언어를 고르거나, 동적 언어라도 타입 힌트가 있는 쪽을 고르는 게 낫다
  - 다큐멘터리가 나왔거나 발표됐던 걸로 기억하는데, 그 영향일 수도 있음

- 이건 정말 큼. **Jank**가 발표된 이후 Clojure 생태계에서 이렇게 기대된 적이 없었음

- 프런트엔드에서 **JavaScript 대안**이 obscure한 수준을 넘어 실제로 자리 잡았으면 좋겠음  
  ClojureScript 같은 걸 써보고 싶지만, 개인 사이드 프로젝트 말고 어디에 쓸 수 있을지 상상하기가 어렵다. 이미 백엔드가 Clojure인 조직이라면 도입이 더 쉬울지도 모르겠음
  - 주류 언어가 아니라 동료들이 모를까 봐 걱정하는 건지, 아니면 언어 자체가 버려지거나 나쁘거나 할까 봐 걱정하는 건지 궁금함  
    프로덕션에서는 안 써봤지만, 사이드 프로젝트 몇 개와 가족용 물건은 배포해봤음. ClojureScript의 React 래퍼인 **Reagent**는 솔직히 React 자체보다 더 말이 된다고 느꼈음  
    Hiccup으로 HTML을 만들고, 컴포넌트는 Hiccup DSL 안의 함수일 뿐인데 이 DSL도 사실상 리스트라서 결과가 아주 깔끔함. 정적인 것은 정적으로 보이고, 동적인 것은 분명히 동적으로 보이며, 일반 React보다 마법이 훨씬 적게 느껴졌음  
    안 좋게 느낀 건 NPM에서 찾은 비함수형 컴포넌트를 쓰려 할 때였음. 치명적이진 않지만 코드가 못생겨짐. 래퍼로 고칠 수는 있었지만, 일부 JS 라이브러리는 cljs에서 기본 상태가 굉장히 지저분함
  - 겁낼 필요 없음, 정말 좋음. **10년째** 복잡한 앱을 고도로 최적화된 클라이언트 코드로 컴파일하는 데 쓰고 있고, obscure하다고 부르지는 않겠음  
    커뮤니티도 매우 친절하고 성숙함
  - 상상만 하지 말고 작게 시작하면 됨. 팀에서 쓰는 bash 스크립트가 있다면 **Babashka**로 다시 써보면 됨  
    먼저 개인 스크립트부터 바꿔보고 감을 익힌 뒤 장점을 느껴보는 게 좋음. 모든 경우에 더 나은 건 아니지만, 나중에 사람들이 조언을 구하러 올 수 있으니 본인이 충분히 확신해야 함  
    낯선 기술을 들여올 때는 덜 중요한 것을 골라 다시 쓰고 그냥 두는 전략이 좋음. 문제가 되면 되돌리기 쉽고, 사람들이 좋아하기 시작하면 조금씩 늘리면 됨  
    예전에 .NET 조직에 F#을 몰래 들여올 때도 덜 중요한 테스트부터 F#으로 쓰기 시작했음
  - **Gleam**을 써보면 좋음. 프로덕션에서 아주 만족스럽게 쓰고 있음  
    [https://blisswriter.app/](<https://blisswriter.app/>)  
    [https://blog.nestful.app/p/how-we-dropped-vue-for-gleam-and](<https://blog.nestful.app/p/how-we-dropped-vue-for-gleam-and>)
  - [https://hypermedia.systems/](<https://hypermedia.systems/>)를 읽고 나서는 최고의 프런트엔드는 **프런트엔드가 없는 것**이라는 결론에 도달했음

- cljs를 오래 따라가지 않았지만, 원래는 “JavaScript 위의 Clojure” 정도로 소개됐던 걸로 기억함. 적어도 Rich가 처음에는 그렇게 설명했던 것 같음  
  최대한 또 하나의 런타임에 가깝게 만들려는 의도라고 이해했음  
  그런데 이번 변경은 cljs에만 있는 기능을 추가하는 것처럼 보이고, `await`가 이미 `clojure.core`의 키워드라서 Clojure 자체와도 충돌함  
  두 구현이 시간이 지나며 갈라진 건지, 아니면 이 기능이 사용자들에게 그 차이를 감수할 만큼 중요했던 건지 궁금함

- 추가 라이브러리를 넣지 않고 **JavaScript 상호운용성**을 다룰 수 있다는 점에서 중요함  
  오래 빠져 있던 기능이라 이번 릴리스가 꽤 반가움

- async/await 함수를 **CSP**로 감싸는 편이 더 나은 처리 방식 같음. Clojure에는 이미 더 좋은 패턴이 있었음
  - 이번 릴리스는 호스트 언어의 원시 기능을 **ClojureScript에 노출**하는 것에 관한 것임  
    core.async가 사라지는 건 아니고, async/await가 Promise 기반 구현보다 더 잘 맞는다면 core.async의 `.cljs` 부분도 업데이트될 수 있음
  - 여전히 그렇게 할 수 있음. ClojureScript 세계에서는 이미 여러 해 동안 가능했고, 결국 그것들은 Promise일 뿐임  
    이번 새 함수 힌트가 들어와도 그 방식이 사라지지는 않을 것 같음  
    [https://clojurescript.org/guides/promise-interop#using-promi...](<https://clojurescript.org/guides/promise-interop#using-promises-with-core-async>)

- 이걸 어떻게 받아들여야 할지 잘 모르겠음. **core.async**의 요지 중 하나가 이런 것들을 모두 채널로 밀어 넣는 것 아니었나 싶음  
  JavaScript식 `async` 키워드를 갖는 게 업그레이드인지 확신이 안 듦
  - 이건 core.async 같은 추가 의존성을 가져오지 않고 **JS 기능**을 쓰기 위한 것임  
    반드시 쓸 필요는 없고, 여전히 core.async도 쓸 수 있음. 최근 ClojureScript 설문에서 가장 많이 요청된 기능이기도 했음
