1 คะแนน โดย GN⁺ 3 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ClojureScript 1.12.145 มีการเปลี่ยนคอมไพเลอร์ให้คอมไพล์ฟังก์ชันที่ติด hint ^:async ออกมาเป็น JavaScript async function
  • สามารถเขียนฟังก์ชัน ClojureScript ที่รอค่า Promise ด้วย await ได้ ทำให้การทำงานร่วมกับ JavaScript ดีขึ้น
  • ยังสามารถใช้ ^:async กับการทดสอบได้ และตรวจสอบผลลัพธ์ของการเรียกฟังก์ชันแบบอะซิงก์ด้วย await ได้
  • ในแบบสำรวจ Clojure ล่าสุด การรองรับ async functions เป็นคำขอปรับปรุง ClojureScript ด้านการทำงานร่วมกับ JavaScript ที่มีสัดส่วนสูงที่สุด
  • สำหรับกรณีทั่วไปที่ต้องใช้งาน Browser API รุ่นใหม่และไลบรารียอดนิยม ความจำเป็นในการเพิ่ม dependency เพิ่มเติม จะลดลง และสามารถดูรายการการเปลี่ยนแปลงทั้งหมดได้ที่ หัวข้อ 1.12.145 ใน ClojureScript changelog

การใช้ ^:async และ await

  • ClojureScript 1.12.145 มีการเปลี่ยนคอมไพเลอร์ให้คอมไพล์ฟังก์ชันที่ติด hint ^:async ออกมาเป็น JavaScript async function
  • เมื่อ ClojureScript กำหนดเป้าหมายไปที่ ECMAScript 2016 ก็ทำให้สามารถเลือกจุดที่จะปรับปรุงการทำงานร่วมกับ JavaScript ได้อย่างรอบคอบ
  • สามารถเขียนฟังก์ชัน ClojureScript ที่รอค่า Promise ด้วย await ได้
    (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 ได้
    (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 เป็นคำขอปรับปรุง ClojureScript ด้านการทำงานร่วมกับ JavaScript ที่มีสัดส่วนสูงที่สุด
  • การปรับปรุงครั้งนี้ช่วยลดความจำเป็นในการเพิ่ม dependency เพิ่มเติมในกรณีทั่วไปที่ต้องใช้งาน Browser API รุ่นใหม่และไลบรารียอดนิยม
  • ดูรายการการแก้ไข การเปลี่ยนแปลง และการปรับปรุงทั้งหมดได้ที่ หัวข้อ 1.12.145 ใน ClojureScript changelog
  • ClojureScript 1.12.145 มีผลงานจากสมาชิกชุมชน Michiel Borkent

1 ความคิดเห็น

 
GN⁺ 3 시간 전
ความคิดเห็นจาก Hacker News
  • borkdude เป็นคนโพสต์เธรดนี้ และเห็นว่าเขาถูกระบุเป็นผู้มีส่วนร่วมในรีลีสนี้ด้วย
    เหตุผลคัดค้านการรองรับ async/await มานานส่วนใหญ่มีอยู่สองข้อ: ต้องแก้ไขเชิงลึกทั่วทั้งคอมไพเลอร์ CLJS และมีแมโครจากไลบรารีอย่าง Promesa ที่ให้ความสะดวกคล้ายกันอยู่แล้ว
    นอกจากนี้ก็มีคนบอกว่าใช้ core.async ก็พอ หรือภาษาแบบเน้น expression ไม่ค่อยเข้ากับ async/await แต่สิ่งเหล่านั้นใกล้เคียงกับความเห็นส่วนบุคคลมากกว่าจะเป็นเหตุผลหลักที่ถูกพูดซ้ำๆ ในฟอรัม
    ใน Clojurians Slack นั้น borkdude เคยบอกว่าเขาไม่ได้มั่นใจว่าการเพิ่มการรองรับเป็นเรื่องที่เป็นไปไม่ได้ และสุดท้ายก็ดูเหมือนเขาจะใช้เวลาลงมือทำจนสำเร็จ ขอบคุณมากจริงๆ

    • ดูเหมือนว่า Borkdude จะเริ่มจากการทำ async/await ใน Squint ซึ่งเป็นอิมพลีเมนเทชันทางเลือกของ ClojureScript ของเขาเองเพื่อพิสูจน์ว่าทำได้ แล้วค่อยนำสิ่งที่เรียนรู้ตอนนั้นกลับเข้ามาสู่คอมไพเลอร์ CLJS หลัก
  • เรื่องที่น่าสนใจคือ ClojureScript รองรับพาราไดม์ asynchronous ผ่านไลบรารี core.async มานานมากแล้ว ก่อนที่ JavaScript จะมี async/await เสียอีก
    ไม่ได้จะลดคุณค่าของรีลีสนี้เลย แค่อยากบอกว่าการเพิ่มไลบรารีเข้า dependency เพียงตัวเดียวแล้วได้ใช้ความสามารถภาษาใหม่ที่ยังไม่มีในภาษาโฮสต์นั้นเท่มาก Clojure เจ๋งจริง

    • ใช่เลย ผมใช้มันมาเยอะและมันก็ทำงานได้ดี แม้จะมีความแปลกๆ อยู่บ้าง แต่จริงๆ แล้วเรามี async/await กันมาเกิน 10 ปีแล้ว
      น่าจะได้รู้เรื่องนี้จากการบรรยายของ David Nolen
      หลังจากนั้นผมก็ค่อยๆ ขยับไปทางใช้ JavaScript ในฝั่งฟรอนต์เอนด์ให้น้อยที่สุด และ SSE เป็นแบบทางเดียวซึ่งสวยงามในแง่นั้น ดีใจที่เดี๋ยวนี้นักพัฒนาจากหลายภาษาเริ่มสนใจ SSE กันมากขึ้น
      งานพูดล่าสุดของ David Nolen ชื่อ “A ClojureScript Survival Kit” ก็ดีมาก: https://youtu.be/BeE00vGC36E
      ต่อให้อธิบายความขอบคุณที่มีต่อสิ่งที่ David “Swannodette” Nolen ทำมาตั้งแต่ยุคแรกของ ClojureScript และ core.async ก็ยังไม่พอ สิ่งที่น่าทึ่งเป็นพิเศษในทอล์กนี้คือ เขาดูตื่นเต้นจริงๆ กับแนวทางที่ละ ClojureScript ไปใช้ Clojure ฝั่งเซิร์ฟเวอร์ล้วนๆ กับ server-sent events และ JavaScript เพียงเล็กน้อย
      เดโมจริงเริ่มราวๆ นาที 26:30 หลังจากแสดงการใช้ทรัพยากรของเว็บแอปที่รันบนไคลเอนต์ เขาก็โชว์เว็บแอปเดียวกันที่รันบนเซิร์ฟเวอร์และ push แบบทางเดียวมายังไคลเอนต์ด้วย SSE ซึ่งการใช้ทรัพยากรแทบจะเป็นศูนย์ ดูทรงพลังมาก
      อาจไม่เหมาะกับทุกกรณี แต่การใช้ไลบรารีสำหรับแก้ไข DOM เพียงน้อยนิดทำให้เข้าใจเว็บแอปและสถานะของมันได้ง่ายขึ้นมาก แต่ก่อนผมต้องเปิดทั้ง REPL ของ Clojure และ REPL ของ ClojureScript พร้อมกัน และต้องรับมือกับทราฟฟิกสองทางกับสถานะที่ทำซ้ำได้ยากเยอะมาก ตอนนี้เร็วกว่าและทำซ้ำได้ง่ายกว่ามาก
    • จริง แต่ในปี 2026 ก็มีเหตุผลมากมายที่จะ หลีกเลี่ยง core.async
      ผลลัพธ์ JavaScript มีขนาดใหญ่ขึ้น ไม่มีโมเดลข้อผิดพลาดในตัว และเมื่อมีปัญหาก็จะถูกแปลงเป็นโค้ด state machine ที่อ่านและดีบักยาก
      แถมแมโคร go ก็แปลงโค้ดนอก S-expression ของตัวเองไม่ได้ จึงผลักดันให้ฟังก์ชันโตเกินความจำเป็น
      อย่างที่คนจาก Cognitect เคยพูดไว้ว่า “core.async คือเรื่องไร้สาระที่งดงาม”
  • ค่อนข้างแปลกใจที่พักหลังนี้เห็น Clojure/ClojureScript บนโซเชียลบ่อยขึ้นแบบกะทันหัน
    ผมเคยใช้มันในงานอยู่หลายปีราวปี 2012 แต่ก็ย้ายออกจาก JVM ไปหาภาษาฟังก์ชันที่มี type เหมือนอีกหลายคน
    ความสนใจที่เพิ่มขึ้นตอนนี้เป็นเพราะ agentic coding หรือเปล่า? เพราะไม่มี type checking และมี syntax error แบบประหลาดๆ หรือคำสงวนให้น้อยกว่า เลยไล่อ่านโค้ดได้เร็วขึ้น? หรือว่าการกลับมาของ S-expression กำลังจะมาถึง

    • ส่วนตัวผมย้ายจากภาษาฟังก์ชันที่มี type มา ClojureScript แล้วต่อมาเป็น Clojure ราว 10 ปีก่อน
      codebase Clojure จริงจังที่ผมรู้จักมักลงทุนกับ test suite มาก ดังนั้นถ้าเพิ่มทักษะให้ AI รู้จักใช้ test suite ให้มีประสิทธิภาพ มันก็น่าจะวิ่งได้ดีทีเดียว
      เพื่อนร่วมงานบางคนก็ปล่อยให้ agent โต้ตอบกับ REPL เลย และบอกว่าเร็วขึ้นเพราะไม่ต้องเสียค่าเริ่มต้นทุกครั้ง ผมขี้เกียจเกินกว่าจะทำถึงขั้นนั้น แต่ตอนนี้ก็เร็วพออยู่แล้ว
      Clojure มีส่วนที่เกะกะน้อยมาก ทุกอย่างเป็นจริงหมด ยกเว้น false และ nil, ไม่มีตารางลำดับความสำคัญของ operator และตัวภาษาแกนกลางก็รองรับโครงสร้างข้อมูลแบบ immutable และ persistent เป็นค่าเริ่มต้น
      ทุกอย่างเป็น expression ไม่ใช่โครงสร้างที่ปนกันระหว่าง operator กับ expression และ map, reduce, filter ก็มีมาให้ในตัวและใช้กันเป็นปกติในโค้ดทั่วไป
      โค้ด Clojure ที่เขียนไว้เมื่อ 10 ปีก่อนก็น่าจะยังรันได้ในวันนี้ และทั้ง ecosystem กับผู้ออกแบบภาษาก็มองการทำโค้ดเก่าพังเป็นเรื่องต้องห้าม
      จากภาษาที่เคยใช้มา มันเป็นภาษาที่ให้อิสระในการถ่ายทอดความคิดมากที่สุดและปวดหัวน้อยที่สุด Flowstorm ซึ่งเป็นเหมือน reverse debugger โดยพฤตินัย ก็เป็นเครื่องมือในฝันสำหรับการเขียนโปรแกรม
      ถ้าอยากเขียนโค้ดแบบสบายใจ มันเป็นภาษาที่ดีมาก ในทางกลับกัน ผู้ใช้ส่วนใหญ่กลับมองสิ่งนี้เป็นเรื่องปกติ เลยไม่ค่อยพูดถึงกันมาก
      ในบรรดาโปรแกรมเมอร์ที่ใช้ Clojure เชิงพาณิชย์ ก็มีหลายคนที่ไม่ได้เข้าใจภาษาอย่างลึกซึ้งและเลยไม่ได้มีความสุขนัก มักเป็นคนที่ไม่ได้เลือกมันเองหรือยังไม่พร้อม และผมคิดว่าก่อนจะใช้ Clojure คุณควรผ่านความไม่ชอบในภาษาอื่นๆ มาสัก 10 ปี
      วิดีโอเกี่ยวกับซอฟต์แวร์ของ Rich Hickey ผู้สร้าง Clojure นั้นดังและมีอิทธิพลก็จริง แต่ไม่ได้แปลว่าเพื่อนร่วมงานของคุณจะเคยดูหรือสนใจมัน
    • ความสนใจที่เพิ่มขึ้นล่าสุดน่าจะมาจากการปล่อย สารคดี Clojure ด้วย: https://clojure.org/about/documentary
    • อีกจุดเด่นที่เข้ากับ agentic coding คือ การพัฒนาแบบขับเคลื่อนด้วย REPL ผมไม่เข้าใจเหมือนกันว่าทำไมในภาษาอื่นที่รองรับได้ในทางทฤษฎี วิธีนี้ถึงไม่แพร่หลายกว่านี้
    • ผมลองทำ agentic coding กับหลายภาษาแล้ว และ ภาษาที่มี type เข้ากันได้ดีกว่ามาก เพราะระบบ type แทบจะช่วยแก้ข้อผิดพลาดที่ agent มโนขึ้นมาให้ โดยเฉพาะเวลาทำรีแฟกเตอร์ครั้งใหญ่
      การจัดการ codebase Python ขนาดใหญ่ที่ไม่มี type ด้วย AI นั้นเหนื่อยมาก ส่วนที่ไม่มี test ครอบอยู่ก็ต้องคอยเช็กอย่างน่าเบื่อว่ามันยังไม่พัง
      ยิ่งระบบ type แข็งแรงยิ่งดี และเพราะโมเดล AI เรียนจากโค้ด ภาษาที่เป็นที่นิยมกว่าก็น่าจะให้ผลลัพธ์ดีกว่า ClojureScript นั้นดี แต่ไม่ใช่ภาษากระแสหลัก ดังนั้นผมคาดว่า AI จะทำงานกับมันได้แย่กว่า JavaScript
      สุดท้ายถ้าคิดถึง AI เป็นหลัก ก็ควรเลือกภาษาที่มี type หรืออย่างน้อยภาษาที่เป็น dynamic แต่มี type hint
    • จำได้ว่ามีสารคดีออกมาหรือมีการประกาศอะไรสักอย่าง นั่นอาจเป็นสาเหตุก็ได้
  • นี่เป็นเรื่องใหญ่จริงๆ วงการ Clojure ไม่ได้รู้สึกตื่นเต้นแบบนี้ตั้งแต่มีการเปิดตัว Jank แล้ว

  • ผมอยากให้ ทางเลือกแทน JavaScript ในฝั่งฟรอนต์เอนด์ก้าวพ้นระดับ niche แล้วกลายเป็นของจริงเสียที
    ผมอยากลองใช้ของอย่าง ClojureScript แต่ก็ยังนึกไม่ออกว่าจะใช้ที่ไหนนอกจากโปรเจ็กต์เล่นส่วนตัว ถ้าเป็นองค์กรที่แบ็กเอนด์ใช้ Clojure อยู่แล้วก็คงนำมาใช้ได้ง่ายกว่า

    • สงสัยว่าคุณกังวลว่าเพื่อนร่วมงานจะไม่รู้จักเพราะมันไม่ใช่ภาษากระแสหลัก หรือกังวลว่าตัวภาษาจะถูกทิ้งหรือไม่ดีกันแน่
      ผมยังไม่เคยใช้ในโปรดักชัน แต่เคย deploy โปรเจ็กต์ส่วนตัวไม่กี่ตัวกับของใช้ในบ้านอยู่บ้าง Reagent ซึ่งเป็น React wrapper ของ ClojureScript นั้นพูดตามตรงรู้สึกสมเหตุสมผลกว่า React เองเสียอีก
      คุณสร้าง HTML ด้วย Hiccup และคอมโพเนนต์ก็เป็นแค่ฟังก์ชันภายใน Hiccup DSL ซึ่ง DSL นี้ก็แทบจะเป็น list อยู่แล้ว เลยทำให้ผลลัพธ์ออกมาสะอาดมาก สิ่งที่เป็น static ก็ดู static และสิ่งที่เป็น dynamic ก็ดู dynamic ชัดเจน รู้สึกว่ามีเวทมนตร์น้อยกว่า React ปกติมาก
      สิ่งที่แย่คือตอนจะใช้คอมโพเนนต์ที่ไม่เป็นฟังก์ชันจาก NPM ไม่ถึงกับร้ายแรงแต่โค้ดจะดูไม่สวย แก้ด้วย wrapper ได้ แต่ไลบรารี JS บางตัวใน cljs นั้นสภาพตั้งต้นค่อนข้างรกมาก
    • ไม่ต้องกลัว มันดีจริงๆ ผมใช้มันมา 10 ปีแล้ว เพื่อคอมไพล์แอปซับซ้อนเป็นโค้ดฝั่งไคลเอนต์ที่ optimize สูงมาก และคงไม่เรียกมันว่า obscure
      ชุมชนก็เป็นมิตรและ成熟มาก
    • อย่าเอาแต่จินตนาการ ลองเริ่มจากของเล็กๆ ก็พอ ถ้าทีมคุณมี bash script อยู่ ก็ลองเขียนใหม่ด้วย Babashka
      ลองเปลี่ยนสคริปต์ส่วนตัวก่อนเพื่อจับทางและสัมผัสข้อดี ไม่ได้ดีกว่าทุกกรณี แต่ภายหลังคนอื่นอาจมาขอคำแนะนำจากคุณ ดังนั้นคุณควรมั่นใจกับมันพอสมควร
      เวลาจะนำเทคโนโลยีที่คนไม่คุ้นเข้ามา กลยุทธ์ที่ดีคือเลือกอะไรที่ไม่สำคัญมากมาเขียนใหม่แล้วปล่อยไว้ ถ้ามีปัญหาก็ย้อนกลับได้ง่าย และถ้าคนเริ่มชอบค่อยๆ ขยายเพิ่ม
      ตอนก่อนเคยลักลอบนำ F# เข้าองค์กร .NET ผมก็เริ่มจากเขียนเทสต์ที่ไม่สำคัญนักด้วย F# ก่อน
    • ลองดู Gleam ก็ได้ ผมใช้ในโปรดักชันและพอใจมาก
      https://blisswriter.app/
      https://blog.nestful.app/p/how-we-dropped-vue-for-gleam-and
    • หลังจากอ่าน https://hypermedia.systems/ แล้ว ผมก็ได้ข้อสรุปว่าฟรอนต์เอนด์ที่ดีที่สุดคือ ไม่มีฟรอนต์เอนด์
  • ผมไม่ได้ตาม cljs มานานแล้ว แต่จำได้ว่าเดิมทีมันถูกอธิบายประมาณว่าเป็น “Clojure บน JavaScript” อย่างน้อยก็เหมือน Rich จะเคยอธิบายแบบนั้นในช่วงแรก
    ผมเข้าใจว่าเจตนาคือทำให้มันใกล้เคียงอีกหนึ่ง runtime ให้มากที่สุด
    แต่การเปลี่ยนแปลงครั้งนี้ดูเหมือนจะเพิ่มความสามารถที่มีเฉพาะใน cljs และ await ก็ชนกับคีย์เวิร์ดใน clojure.core ของ Clojure เองอยู่แล้ว
    เลยสงสัยว่าสองอิมพลีเมนเทชันนี้ค่อยๆ แยกจากกันไปตามเวลา หรือว่าฟีเจอร์นี้สำคัญกับผู้ใช้มากพอให้ยอมรับความต่างนั้น

  • เรื่องนี้สำคัญเพราะทำให้จัดการ JavaScript interop ได้โดยไม่ต้องเพิ่มไลบรารีเสริม
    เป็นฟีเจอร์ที่ขาดหายไปนานมาก และรีลีสนี้ก็น่ายินดีทีเดียว

  • ผมว่าการเอาฟังก์ชัน async/await ไปครอบด้วย CSP น่าจะเป็นวิธีจัดการที่ดีกว่า Clojure มีแพตเทิร์นที่ดีกว่านี้อยู่แล้ว

    • รีลีสนี้เกี่ยวกับการ เปิดให้ ClojureScript ใช้ความสามารถ native ของภาษาโฮสต์
      ไม่ได้หมายความว่า core.async จะหายไป และถ้า async/await เหมาะกว่าการใช้งานแบบ Promise บางทีส่วน .cljs ของ core.async ก็อาจถูกอัปเดตได้
    • คุณยังทำแบบนั้นได้อยู่ ในโลกของ ClojureScript ก็ทำได้มาหลายปีแล้ว และท้ายที่สุดพวกมันก็เป็นแค่ Promise
      ต่อให้มี function hint ใหม่นี้เข้ามา วิธีนั้นก็คงไม่ได้หายไป
      https://clojurescript.org/guides/promise-interop#using-promi...
  • ผมยังไม่แน่ใจว่าควรมองเรื่องนี้อย่างไร จุดสำคัญอย่างหนึ่งของ core.async ไม่ใช่ว่ามันควรดึงทุกอย่างเข้ามาอยู่ใน channel หรอกหรือ
    ผมไม่แน่ใจว่าการมีคีย์เวิร์ด async แบบ JavaScript นั้นเป็นการอัปเกรดจริงหรือเปล่า

    • นี่มีไว้สำหรับใช้ ความสามารถของ JS โดยไม่ต้องพึ่ง dependency เพิ่มอย่าง core.async
      ไม่ได้บังคับว่าต้องใช้ และคุณก็ยังใช้ core.async ต่อไปได้ อีกทั้งมันยังเป็นฟีเจอร์ที่ถูกขอมากที่สุดในแบบสำรวจ ClojureScript ครั้งล่าสุดด้วย