2016-09-02 11 views
5

Tôi đang viết ứng dụng Electron và trong ứng dụng này tôi cần tương tác với một số API Node.js - đọc tệp, nhận các mục nhập thư mục, nghe sự kiện. Tất nhiên, tôi có thể viết ClojureScript giống như cách tôi viết JavaScript, nhưng tôi muốn biết ClojureScripts nhận các API kiểu gọi lại, luồng, EventEmitters là gì và làm cách nào để viết trình bao bọc xung quanh API node.js theo cách mà không nhìn người ngoài hành tinh trong ClojureScript.Chuyển đổi thành ngữ của API node.js thành ClojureScript

Để cụ thể:

  1. Làm thế nào để viết một API mà kết thúc tốt đẹp API gọi lại kiểu Node.js. (ví dụ: fs.readdir)
  2. Làm cách nào để tương tác với API giống như EventEmitter?
  3. (Có thể gần với p.2) Làm cách nào để làm việc với API luồng node.js?

Trả lời

6

Theo kinh nghiệm của tôi, cách đơn giản nhất để xử lý các vấn đề này là sử dụng core.async.

Callback Phong cách

Ví dụ, đọc một thư mục:

(def fs (js/require "fs")) 

(defn read-dir [path] 
    (let [out (async/chan)] 
    (.readdir fs path 
     (fn [err files] 
     (async/put! (if err err files)) 
     (async/close! out))) 
    out)) 

tôi vượt qua kết quả trong một kênh, ngay cả khi kết quả đó là một lỗi. Bằng cách này, người gọi có thể xử lý lỗi bằng cách thực hiện. Ví dụ .:

(let [res (<! (read-dir "."))] 
    (if (instance? js/Error res) 
    (throw res) 
    (do-something res)) 

Trong các dự án riêng của tôi, tôi sử dụng cljs-asynchronize, cho phép bạn chuyển đổi chức năng NodeJS callback phong cách chức năng tương thích core.async. Ví dụ, đây là giống như ví dụ đầu tiên:

(defn read-dir [path] 
    (asynchronize 
    (.readdir fs path ...))) 

Cuối cùng, một cách đẹp hơn xử lý các lỗi thông qua các kênh, cá nhân tôi thấy "Error Handling with Clojure Async" khá hữu ích. Vì vậy, bạn có thể viết mã xử lý lỗi trên như:

(try 
    (let [res (<? (read-dir "."))] 
    (do-something res)) 
    (catch js/Error e 
    (handle-error e)) 

Streams

Suối API thậm chí còn đơn giản hơn:

(defn create-read-stream [path] 
    (let [out (async/chan) 
     stream (.createReadStream fs path)] 
    (.on stream "close" #(async/close! out)) 
    (.on stream "data" #(async/put! out %)) 
    out)) 
+1

Ví dụ về try/catch có hoạt động với đoạn đầu tiên không, mà không có thay đổi? –

+1

Có. Về cơ bản,

1

Tôi nghĩ câu trả lời cho câu hỏi của bạn là "Nó phụ thuộc ".

Luôn xem xét tất cả các tùy chọn. Chỉ vì core.async có ý nghĩa trong một cài đặt không làm cho nó trở thành lựa chọn tốt nhất ở mọi nơi.

Bạn có thể sử dụng cuộc gọi lại bình thường nếu được gọi một lần duy nhất và không yêu cầu sự phối hợp với bất kỳ điều gì khác (ví dụ: fs.readdir).

core.async thật tuyệt vời cho luồng như những thứ bạn nhận được chuỗi sự kiện nhất định mà bạn muốn tích lũy vào kết quả cuối cùng (ví dụ: "data","data","data","close","end").

Lời hứa cũng là một tùy chọn khác.

Phối hợp nhiều hơn bạn cần có ý nghĩa hơn là core.async. Nếu bạn không cần bất kỳ lựa chọn thay thế nào.

Các vấn đề liên quan