mori — это круто, когда @swannodette экспортирует почти все классные вещи из ClojureScript в обычный JavaScript.

Но когда я смотрю на исходный код, кажется возможным перенести почти все функции из ClojureScript в JavaScript, просто используя макрос mori-export. Так что я просто немного попробую то, о чем я всегда мечтал, и что я могу использовать в ванильном JavaScript — core.async.

поэтому я просто разветвляю мори и даю ему имя conjs, чтобы я мог npm install его в моем собственном проекте (я не уверен, что лицензия EPL позволяет мне переименовать его, но он просто называется conjs на npm, библиотека все еще по имени Мори, никогда не собирался брать на себя ответственность).

взять 1

Все, что мне нужно сделать, это очень просто: экспортировать все методы Channel.

(mori-export async.chan async/chan)
(mori-export async.take$ async/take!)
(mori-export async.put$ async/put!)
(mori-export async.doAlts async/do-alts)
(mori-export async.timeout async/timeout)

это одни из самых полезных методов, и тогда он просто работает 😱 хотя пока это просто обратный вызов.

    it('take and put from channel',function(done) {
      var c = async.chan()
      async.take$(c ,function(x){
        expect(x).toBe('something in channel')
        done()
      })
      async.put$(c, 'something in channel')
    })

событие альтернативы работает

    it('race channel', function(done) {
      var c1 = async.chan()
      var c2 = async.chan()
      
      async.doAlts(function(v) {
        expect(mori.get(v, 0)).toBe('c1')
        expect(mori.equals(c1, v.a(1))).toBe(true)
        done()
      },[c1,c2])
      async.put$(c1, 'c1')
      async.put$(c2, 'c2')
    })

взять 2

теперь канал работает, но в уродливом обратном вызове, что я могу сделать, чтобы он выглядел лучше и приятнее, так это сделать его как обещание.

(defn ^:export put [chan val]
 (goog/Promise. (fn [resolve, reject] (async/put! chan val (fn [res] (resolve res))))))
(defn ^:export take [chan]
 (goog/Promise. (fn [resolve, reject] (async/take! chan (fn [res] (resolve res))))))
(defn ^:export alts [chans]
 (goog/Promise. (fn [resolve, reject] (async/do-alts (fn [res] (resolve res)) chans))))

что я делаю, так это просто возвращаю goog.Promise в обещании, как только вызывается обратный вызов put/take, обещание будет разрешено.

Теперь у нас немного лучше выглядящий канал core.async.

async.take(c)
 .then(function(x){
   expect(x).toBe(‘something in channel’)
 })
 .then(done)

но все еще далеко от того, как это должно выглядеть в блоке go core.async.

вы знаете, что блок go — это макрос, который генерирует правильный конечный автомат для соответствующего тела внутри. нет возможности перенести макрос на JavaScript, поскольку макросы расширяются во время компиляции, а не во время выполнения.

Так что я думаю, что это самый красивый core.async, который я могу портировать на ванильный JavaScript, если только вы не используете Babel и не пишете код ES7.

Асинхронная функция

В ES7 предлагается асинхронная функция, и с Babel вы можете использовать ее прямо сейчас. И хорошо, что он совместим с Promise.

var a = mori.async;
(async function(){
  var v = await a.atls([c1,c2])
  expect(v.get(0)).toBe('c1')
  expect(mori.equals(c1, v.get(1))).toBe(true)
})()

(async function(){
  await a.put(c1, 'c1')
  console.log('put c1 into c1')
})()

Я предполагаю, что мой проект использует babel, поэтому я полностью доволен портом core.async из ClojureScript, даже если без babel обещание все еще достаточно хорошо для CSP в стиле JavaScript.

И вот еще…

Если вы много программируете на JavaScript, вы, вероятно, согласитесь, что у Immutable.js стиль JS лучше, чем у mori.

mori.get(vector, 1)
// no, ^^^ it's clojure flavor
// this vvvvv is javascript
vector.get(1)

Но мне нравится игра Мори. Так что я думаю, что одна вещь, которую я могу сделать, это сделать структуру данных mori более похожей на обычную структуру данных JavaScript API.

поэтому я написал простой макрос для экспорта всех методов в прототип структуры данных.

(defmacro property-export [exportp corep]
 `(js/goog.exportSymbol
 ~(str “mori.” exportp)
 (fn [& args#] (apply ~corep (cons (~’js* “this”) args#)))))

поэтому, когда я экспортирую вектор, get motod

(property-export “Vector.prototype.get” cljs.core/get)

Я смогу использовать as get в качестве метода вместо частного метода uglified

с помощью этого макроса я экспортировал все методы

describe(‘Vector’, function() {
 var vec = m.vector(1,2,3,4)
 it(‘expose methods’,function() {
 expect(vec.get(1)).toBe(2);
 expect(vec.conj(5,6).toString()).toBe(‘[1 2 3 4 5 6]’)
 expect(vec.empty().toString()).toBe(‘[]’)
 expect(vec.equiv(m.vector(1,2,3,4))).toBe(true)
 expect(vec.count()).toBe(4)
 expect(vec.assoc(3, 6).toString()).toBe(‘[1 2 3 6]’)
 expect(vec.reduce(function(acc,x){return acc+x},0)).toBe(10)
 expect(vec.kvReduce(function(acc, k, v){return acc+k+v},0)).toBe(16)
 })
})

плавник

Я все еще получаю удовольствие и использую его в своем стороннем проекте, так что это довольно экспериментально и WIP, получайте удовольствие от него, если вам нравится использовать все преимущества ClojureScript и использовать их в JavaScript нативно.

не стесняйтесь форкнуть и запрос на вытягивание приветствуется.

доступно в нпм

npm install con.js

и rawgit cdn для браузера

https://rawgit.com/jcouyang/conjs/master/mori.js

получайте удовольствие 😹