Pull to refresh

Comments 31

Я правильно понимаю, что вы умышленно форсите рендер через каждые 500мс?
widget = require("widget")
do_render = () -> React.render(widget(state), domelement) if domelement?
render_process = () ->
    try
        do_render()
    catch error
        console.log error
    setTimeout(render_process, 500)

Реакт сам исходя из состояния компонента (state) определяет, нужно ли ре-рендериться, вам не нужно форсить ре-рендер. Всё, что вам нужно — лишь описать зависимость конечного dom дерева компонента от его state. При изменении state (вызов this.setState) реакт будет смотреть, поменялось ли конечное dom дерево и, если поменялось, то найдёт минимально необходимые изменения в dom и произведёт их.
Код далеко не оптимален, более того, некорректен.
if type_a == type_b
        switch type_a
            when "[object Undefined]" then a == b #можно сразу возвращать true
            when "[object Boolean]" then a == b 
            when "[object Number]" then a == b # а вы точно хотите на +0 == -0 получать true? это не сарказм, это кривая система неточного равенства.
            when "[object String]" then a == b
            when "[object Function]" then a.toString() == b.toString() #не учитывается возможность существования функторов; не учитывается возможность оверлоада .toString, не учитываются нативные и binded-функции, которые возвращают function () { [native code] }
            when "[object Null]" then a == b #можно сразу возвращать true
            when "[object Array]" #не сравниваете свойства у массива. Да, в JS массив тоже объект и может иметь свойства.
                len_a = a.length
                len_b = b.length
                if len_a == len_b
                    [0..len_a].every (n) -> equal(a[n], b[n])
                else
                    false
            when "[object Object]"
                keys_a = Object.keys(a).sort() #не учитывается возможность существования defined Properties, сравнение прототипов
                keys_b = Object.keys(b).sort()
                if equal(keys_a, keys_b)
                    keys_a.every (k) -> equal(a[k], b[k])
                else
                    false


Не пишите на «чисто функциональном» стиле на JS. Он не предназначен для этого, вы не сможете получить именно то, чего хотите, без иммутабельности.
Дело в том что я в своём коде не использую какие-то сложные, неоднозначные и уж тем более ООП стороны js.

а вы точно хотите на +0 == -0 получать true?
да :)

В моём понимании [head, tail...] — это просто список, а не объект и я никогда не переопределю для него поле length, в моём понимании length тут вообще не поле а метод (хотя судя по тому как он «вызывается» — это не так)

{key: value} — для меня не объект а просто map, хэш-таблица с парами key — value где key и value — любые js-данные, и поэтому я никогда не буду что-то там делать с прототипами

Насчёт when "[object Function]" then a.toString() == b.toString() — реально очень скользкий момент, но я увы так и не смог придумать как ещё можно сравнить две функции по значению. Разыменовывания указателя в js я так и не нашёл, это решило бы все подобные проблемы :(

a == b для примитивов у меня написано просто для красоты и однородности :) Да и мало ли что, просто изучать детально и глубоко реализацию всех типов данных в js не было ни времени ни сил ни желания
>> а вы точно хотите на +0 == -0 получать true?
> да :)
Это ваше дело, я просто уточнил, как я и писал. Кстати, == по перфомансу еще и медленнее чем ===

> В моём понимании [head, tail...] — это просто список, а не объект и я никогда не переопределю для него поле length, в моём понимании length тут вообще не поле а метод (хотя судя по тому как он «вызывается» — это не так)
> {key: value} — для меня не объект а просто map, хэш-таблица с парами key — value где key и value — любые js-данные, и поэтому я никогда не буду что-то там делать с прототипами

Вы же планируете работать c DOM API? или Node.js APIs? Или вы делаете чистые функции на JS просто так? Все куда более неоднозначно, чем кажется.
Кстати насчёт == || === и прочего — в coffeescript многие подобные скользкие моменты решены, например == всегда разворачивается в ===, слова return нет — всегда возвращается результат последнего выражения в функции итп

Насчёт работы с реальным продакшном у меня сложилась поределённая схема, вот пример:

1) Вот html-страничка, нас интересует вот этот блок который собственно будет отрисовываться в jreact, там будет происходить весь экшн

github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/index.jade#L12

2) Вот сам виджет который будет рисоваться пользователю в зависимости от состояния state

github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/widget.jreact

3) Когда DOM первый раз построился — мы врубаем jreact через актор

github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/scripts/app.coffee#L88-91

4) А дальше уже всё в абсолютно свободном плавании — коллбэки висящие на кнопках, что-то летящее с сервера в вебсокет — всё это отправляет сообщения актору

github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/scripts/app.coffee#L51

который строго в порядке очереди их вызывает, обновляя свой внутренний state

5) Периодически опрашиваем актор — получаем копию его текущего state и передаём в react который рисует пользователю страничку

github.com/timCF/megaweb/blob/c90ede0e0c48373712695fb5a3e3b77247c6f6a7/app/scripts/app.coffee#L68
Да, про == забыл.

Про
> Периодически опрашиваем актор — получаем копию его текущего state и передаём в react который рисует пользователю страничку
Не кажется ли, что реактивный подход был бы лучше?
скорее всего глобальный state + react будет быстрее, но конечно чистота тут уже нарушится :)
Сейчас использую глобальный state с чистыми функциями. Получается довольно интересно. Использую github.com/Yomguithereal/baobab.

Схема работы у меня такая:
В корневом виджете создается глобальный стейт (может получаться с помощью DI). Далее мы триггерим action в componentWillMount. Этот action занимается тем, что получает нужные данные с сервера асинхронно и сетит начальный стейт на основе текущих props. Actions представляют собой объект, который тупо собирает несколько функций, пример:
function setField(value {
   state.set(['path_to_field'], value)
}

export default {
  setField
}
Почему чистота нарушится? Глобальный state — это очень даже чисто. Разумеется, тут понадобятся дополнительные абстракции для работы с ним. Линзы, к примеру.
Две функции прекрасно сравниваются оператором ===, если очень надо. Все остальные способы будут врать на простейших замыканиях.

Кстати, в функциональных языках функции вообще нельзя сравнивать!
смотря в каких языках :)
в эрланге например можно

насчёт js — нет, в лоб это не работает

coffee> f1 = () -> 123
[Function]
coffee> f2 = () -> 123
[Function]
coffee> f1 == f2
false
coffee> f1.toString() == f2.toString()
true

можно конечно использовать toString, но как было верно подмечено это костыль :)
У вас f1 и f2 — это две совершенно разные функции. То, что они выдают одинаковые значения на всей области определения — это просто случайность.
Вот вам загадка:

ff = x -> () -> x;
f1 = ff 1
f2 = ff 2

console.log f1.toString() == f2.toString() // true


Но являются ли функции одинаковыми?
Гм, а в каком месте это противоречит предыдущему оратору?
В том, что вызов .toString() для сравнения — это не просто костыль, а грубая ошибка.
С этим не спорю, просто из вашего предыдущего комментария этого не следует. Ваш пример по функционалу идентичен примеру предыдущего комментатора.
я не хочу холиваров на хабре и вообще хочу конструктивного диалога :)
то что в начальном тексте у меня ошибка это ясно, глупо клонировать функцию вот так

when "[object Function]" then some.bind({})

а потом пытаться сравнивать вот так

when "[object Function]" then a.toString() == b.toString()

Но вот я поковырялся с интерпретатором, и в итоге прикрепляю скриншот того что получилось. Я вижу что функции тут — клонируемые по значению абстракции, и это парадоксально но похоже что сравниваются они тоже по значению. Прикрепляю скриншот чтобы ты не подумал что я жульничаю и набираю это всё в текстовом редакторе :)

Похоже всё работает как надо, но конечно если придерживаться определённых правил.

точнее даже вот так. я думаю идея понятна :)
правда не знаю можно ли из этого извлечь что-то для моей задачи, подумаю над этим на досуге

Извиняюсь, но у вас каша в голове. Разумеется, если вы делаете присваивание f1 = f2, то они почему-то оказываются одинаковыми…
но почему тогда вот тут

habrastorage.org/files/91d/83a/ad4/91d83aad404b4e6d8d19082e95e98c33.png

после строчки

f1 = () -> 123

f2 тоже не изменилась, если при присваивании функций данные передаются по указателю? Если в таком случае после второй строчки

f2 = new () -> f1

память всё же выделяется под новую функцию — то тогда почему в третьей строчке они равны?
Никаких указателей на переменную — присваивание всегда происходит по значению.

PS вы правда не видите, что new () -> f1 — это то же самое, что и просто f1?
«Никаких указателей на переменную — присваивание всегда происходит по значению.»

Это конечно прекрасно :)

Но похоже что это не работает для списков и структур

В данном случае, само значение является ссылкой. А указателей на переменную как не было, так и нет:

a = {k : 1}
b = a
console.log b // {k : 1}

a = {k : 2}
console.log b // все еще {k : 1}
Ясно, спасибо
Видимо реально проще использовать fay или purescript :)
+0 === -0 даже с точным равенством и тут ничего кривого нет, как и в том, что 1/(+0) !== 1/(-0) или NaN !== NaN.
FortranErlang-программист напишет FortranErlang-программу на любом языке программирования? :)
В принципе да :) Такой подход имеет ряд плюсов

1) Однородность данных: сервер кидает клиенту через вебсокет сообщения которые содержат какие-то данные. Сервер написан на эрланге. Там нет никаких объектов — есть binaries, integers, floats, lists, maps. Именно в таком виде данные приходят клиенту. Если мы продолжим работать с этими данными именно как с данными а не как с объектами — это здорово снизит накладные расходы на написание всяческого рода классов, конструкторов, и прочих адаптеров erlang_data <=> js_data.

То же самое правило я кстати использую и по отношению в взаимодействию сервер <=> бд. То есть называю поля в эрланговских структурах в точности именами столбцов бд. Это реально здорово снижает накладные расходы, количество кода, увеличивает читаемость и прозрачность.

2) Мне гораздо проще читать / писать код, если он написан в парадигме моего основного языка.
Это все уже сделано. Называется N2O.
Есть даже компилятор из эрланга в JavaScript SHEN.
UFO landed and left these words here
Спасибо вам за статью. Должен с вами не согласится по поводу выбора coffeescript'а. С виду данный язык хорош но вот когда начинаешь использовать его на настоящих проектах тут и ползут непонятки, Поль там поставил пробел, Жак здесь забыл запятую и пошло поехало. Мне кажется с такими неясностями в дизайне кофий скриптовский на роль функционального языка ну никак не тянет, его можно попрововать притянуть или натянуть но из этого ничего путного не выйдет. Кстати вы не упомятули о FunScript и Scala.js которые не просто подмоножества но они являются настоящими закоренелыми функциональными языками транслируеммыми в js.
Only those users with full accounts are able to leave comments. Log in, please.