Как стать автором
Обновить

Комментарии 13

Что-то потоки какие-то переусложненные и при этом довольно слабые.


Если сравнивать с rx, то, судя по приведенному коду, видно следующее:


  1. Любой поток работает как BehaviorSubject, т.е. хранит последнее значение. Это вроде бы удобно — но совершенно бесполезно для потоков, которые не представляют какое-то значение (и пример такого потока — как раз useInterval).


  2. Нет оператора switchMap, а ведь это один из наиболее важных операторов rx.js


    Смотрите как могла выглядеть функция useInterval с оператором switchMap:


    function useInterval(delay$) {
        return delay$.switchMap(delay => {
            const res = stream()
            const id = setInterval(res, delay, delay);
            res.end.map(() => clearInterval(id));
            return res;
        })
    }

  3. Не различаются окончание потока и его отмена.


1. useInterval — это контекст для вычисления потока count()
// ссылка на поток tick
const tick = useInterval({ delay })

// здесь мы создаем дочерний поток для побочных действий
// каждый раз когда запускается новый интервал мы увеличиваем счетчик
tick.map(() => count( count() + 1 ))
// после каждого увеличения счетчика вызываем отрисовку
count.map(m.redraw)

2. switchMap реализован идеоматичным для потоков образом в контексте
theirDelay()

3. parent.end касается только потомков, сам поток родитель parent() остается активным
собственно end и это и есть отмена дочернего потока.
Что бы закрыть контекст дочернего потока, можно использовать stream.SKIP
parent.map( ()=> stream.SKIP )
useInterval — это контекст для вычисления потока count()

И что из этого следует? Кстати, count тоже реализован неоптимально, специально же для таких случаев придуман scan:


const count = Stream.scan(acc => acc+1, 0, tick);

switchMap реализован идеоматичным для потоков образом в контексте theirDelay()

Не вижу ничего похожего на switchMap.


parent.end касается только потомков, сам поток родитель parent() остается активным собственно end и это и есть отмена дочернего потока.

Во-первых, нет, не остаётся. Если сделать parent.end(true) — то поток parent перейдёт в состояние "ended", в котором он игнорирует любые попытки обновления.


Во-вторых, как эти рассуждения отменяют невозможность различить что произошло с потоком, был ли он отменён снаружи или "иссяк" изнутри?


Что бы закрыть контекст дочернего потока, можно использовать stream.SKIP parent.map( ()=> stream.SKIP )

Нет, stream.SKIP не закрывает никакого контекста, это просто пропуск обновления.

1. контекст нужен, для того, что бы вычислять в контексте.
2. автор оригинала не хотел использовать scan, я так думаю.
3. theirDelay это не switchMap, это theirDelay, который можно реализовать даже не трогая контекст useInterval.
4. A stream can stop affecting its dependent streams by calling stream.end(true). This effectively removes the connection between a stream and its dependent streams.
mithril.js.org/stream.html#ended-state
5. нам не нужно вычислять, мы точно знаем, что хотим закрыть поток
6. A special value that can be returned to stream callbacks to skip execution of downstreams
You can prevent dependent streams from being updated by returning the special value stream.SKIP
var skipped = stream.combine(function(stream) {
return stream.SKIP
}, [stream(1)])

skipped.map(function() {
// never runs
})
контекст нужен, для того, что бы вычислять в контексте.

Я всё ещё не понимаю что вы пытаетесь сказать.


theirDelay это не switchMap, это theirDelay, который можно реализовать даже не трогая контекст useInterval.

Ну так где реализация switchMap-то? Вы писали, что он где-то там идеоматичным образом реализован.


A stream can stop affecting its dependent streams by calling stream.end(true). This effectively removes the connection between a stream and its dependent streams.

И что из этого следует?


нам не нужно вычислять, мы точно знаем, что хотим закрыть поток

А если нужно?


A special value that can be returned to stream callbacks to skip execution of downstreams

И?

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

knockout намного умнее этой библиотеки, он, к примеру, вот в этой ситуации без труда устраняет как лишний пересчёт потока c, так и лишний вызов console.log:


ko.options.deferUpdates = true;

const x = ko.observable(1)
const y = ko.observable(2)
const z = ko.observable(3)
const a = ko.pureComputed(() => x() - y())
const b = ko.pureComputed(() => y() + z())
const c = ko.pureComputed(() => a() + b())
ko.computed(() => console.log(c()))
y(6);

А ещё knockout не требует явно указывать зависимости.

вообще забавно, как раз в полгода выходят новые прорывные фреймворки, которые слегка надрезал — и вот он, нокаут
knockout — фреймворк, stream — функция, сама по себе, применение не зависит,
Спасибо вам за отличный перевод, как по мне, он довольно качественный, было приятно читать. Но все же не могу удержаться от того, чтобы сказать, что хабру, да и не только хабру, нужен специальный человек, корректор, чтобы следил за грамотностью текста
Используем подобную агрегацию большого потока состояний с задержкой в системах оперативного мониторинга, но не знал что есть такая структура данных как stream. Будет повод порефакторить. Спасибо за статью.

Лучше посмотрите в сторону rx.js, там куда больше возможностей по манипуляции потоками. И лучше изоляция поставщиков и потребителей.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории