Чем реактивное программирование отличается от программирования, управляемого событиями?

Я изучаю реактивное программирование и функциональное реактивное программирование на JavaScript. Я очень смущен.

Википедия говорит, что существуют различные способы написания реактивного кода, такие как императивный, объектно-ориентированный и функциональный. Я хочу знать, является ли управление событиями просто еще одним способом написания реактивного кода?

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


person Narayan Prusty    schedule 28.12.2015    source источник


Ответы (5)


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

На практике они связаны, я называю Promises лекарством, открывающим доступ к функциональному реактивному программированию.

+----------------------+--------+-------------+
|                      |  Sync  |    Async    |
+----------------------+--------+-------------+
| Single value or null | Option | Promise     |
| Multiple values      | List   | EventStream |
+----------------------+--------+-------------+

Промисы можно рассматривать как EventStreams с одним элементом, или вы можете думать о EventStreams как о множестве Promises с течением времени.

Обещания можно связать в цепочку, что приближается к реактивному программированию:

getUser() // return promise
   .then((userId) => {
       return fetch("/users/"+userId)
   })
   .then((user) => {
       alert("Fetched user: " + user.name)
   })

То же самое с bacon.js:

const userStream = userIdStream // EventStream of userIds
   .flatMapLatest((userId) => {
       return Bacon.fromPromise(fetch("/users/"+userId))
   })
const userNameStream = userStream.map((user) => user.name)
userNameStream.onValue((user) => {
   alert("Fetched user: " + user.name)
})

Оба фрагмента кода делают одно и то же, но есть большая разница в мышлении: с промисами вы думаете об обработке одного действия с асинхронными шагами понятным образом — мышление императивно, вы делаете все шаг за шагом. С FRP вы говорите, что «поток имен пользователей создается из потока userIds путем применения этих двух шагов преобразования». Когда у вас есть поток имен пользователей, не заботясь о том, откуда они взялись, и говорите: «всякий раз, когда появляется новое имя пользователя, отображайте его для пользователя».

Стиль кодирования FRP поможет вам смоделировать вашу проблему как поток значений (то есть значений, которые меняются со временем) и отношения между этими значениями. Если вы уже знакомы с промисами, начальная кривая обучения будет немного проще, но основное преимущество будет получено только тогда, когда вы начнете думать и моделировать проблему по-другому — возможно (хотя и не очень полезно) выполнять императивное программирование с библиотеками FRP.

person OlliM    schedule 29.12.2015

Чем реактивное программирование отличается от программирования, управляемого событиями?

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

Реактивное программирование работает с данными. В конечном счете, это частный случай программирования, управляемого событиями. Событие: данные изменились. Обработчик события: изменить еще некоторые данные (если применимо). Эта концепция обычно проясняется, когда вы думаете о электронной таблице. Если вы устанавливаете cell1 = cell2 + cell3, это неявно устанавливает два обработчика событий для событий изменения данных cell2 и cell3 для обновления данных cell1. Данные cell1 не имеют такого обработчика событий, потому что никакие ячейки не зависят от его значения.


TL;DR;

Википедия говорит, что существуют различные способы написания реактивного кода, такие как императивный, объектно-ориентированный и функциональный. Я хочу знать, является ли управление событиями просто еще одним способом написания реактивного кода?

Идея управляемого событиями программирования ортогональна идее императивного, объектно-ориентированного и функционального.

  • Императорское программирование: основное внимание уделяется изменению состояния вашей программы для достижения желаемого. Большинство компьютеров являются императивными (в отличие от декларативного программирования), тогда как языки более высокого уровня иногда являются декларативными. Декларативное программирование, напротив, имеет дело с написанием кода, который указывает, ЧТО вы хотите, чтобы он делал, а не КАК вы хотите, чтобы код это делал.
  • Ообъектно-ориентированное Оориентированное программирование : имеет дело с так называемыми объектами или пакетами данных с соответствующими методами. Отличается от функционального программирования тем, что методы имеют доступ к данным, связанным с объектами.
  • Функциональное программирование: имеет дело с многократно используемыми функциями или процедурами, принимающими входные и выходные данные. Это отличается от объектно-ориентированного программирования, поскольку функции традиционно не имеют возможности связывать данные с функцией, кроме входных и выходных данных.

Программирование, управляемое событиями: структурирует вашу программу, чтобы иметь дело ("обрабатывать") что-то еще что происходит в вашей программе ("событие"). Другими словами, он логически структурирует ваш код следующим образом.

When Event1 happens
    do A and B

When Event2 happens
    do B and C

Но есть много способов написать этот код, и на самом деле много способов императивного написания кода, много способов функционального написания и т. д. Вот несколько примеров.

В обязательном порядке (с циклом событий):

while(true)
    // some other code that you need to do...

    if Event1 then
        do A
        do B
    if Event2 then
        do B
        do C

Объектно-ориентированный (с фоновым потоком):

// event queue
events = new EventQueue()

handler = new EventHandler()
// creates background thread
Thread.DoInBackground(handler.listenForEvents(events))

// ... other code ...

// fire an event!
events.enqueue(new Event1())

// other file
class EventHandler
    Func listenForEvents(events)
        while(true)
            while events.count > 0
                newEvent = event.dequeue()
                this.handleEvent(newEvent)
            Thread.Sleep(Time.Seconds(1))

    Func handleEvent(event)
        if event is Event1
            this.A()
            this.B()
        if event is Event2
            this.B()
            this.C()

    Func A()
        // do stuff
        return

    Func B()
        // do stuff
        return

    Func C()
        // do stuff
        return

Функциональный (с языковой поддержкой событий)

on Event(1) do Event1Handler()
on Event(2) do Event2Handler()

Func Event1Handler()
    do A()
    do B()

Func Event2Handler()
    do B()
    do C()

Func A()
    // do stuff
    return

Func B()
    // do stuff
    return

Func C()
    // do stuff
    return

// ... some other code ...

// fire! ... some languages support features like this, and others have
// libraries with APIs that look a lot like this.
fire Event(1)

Как реактивное программирование связано с промисами?

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

  • Спрашивающий: Когда вы закончите делать то, что делаете, вы перезвоните мне?
  • Отвечающий: Конечно, я обещаю

Здесь нет ничего особенного, за исключением того, что это еще один способ представить себе порядок выполнения вашего кода. Например, промисы полезны, когда вы звоните удаленной машине. Промисами можно сказать «перезвони мне, когда вернешься с этого удаленного звонка!». Какую бы библиотеку вы ни использовали, она обещает перезвонить вам, когда получит что-то от удаленной машины. Часто это полезно, потому что позволяет тем временем заняться чем-то другим, не дожидаясь возврата вызова.

Изюминка: существует множество разных стилей кода, но они не играют слишком большой роли в модели управляемого событиями и реактивного программирования. Насколько мне известно, вы можете выполнять управляемое событиями и/или реактивное программирование на большинстве языков.

person Frank Bryce    schedule 28.12.2015
comment
Промисы — это больше, чем просто поток выполнения: они представляют собой модель постоянства, представляющую состояние этого выполнения и его окончательный результат. Поскольку они постоянны, их можно хранить, совместно использовать, ссылаться, передавать. Принимая во внимание, что в чисто управляемой событиями системе вам не хватает истории, если вы начинаете слушать постфактум, и вам (как правило) приходится прослушивать все события, чтобы слышать любые события. Промис дает вам возможность инкапсулировать и подписываться на ограниченный, одноцелевой поток событий, а также проверять состояние этого потока событий в любое время в будущем. - person XML; 07.03.2018
comment
В целом, этот пост — отличное чтение о принципах. Подробнее см.: oreilly.com/ideas/reactive-programming-vs -реактивные-системы - person XML; 07.03.2018
comment
Мне нравится, что ваш ответ лучше принятого, но все это, похоже, сводится к, казалось бы, вечной потребности нашей отрасли в создании новых модных словечек. Ваше утверждение о различии между программированием, управляемым событиями, и так называемым реактивным программированием для меня натянуто. Реактивное программирование имеет дело с данными. В конечном счете, это частный случай программирования, управляемого событиями. Полагаю, только частный случай для тех, кто имеет ограниченное представление о том, что такое событие. В любом случае, смерть анемичным модным словечкам!!! - person Jason Bunting; 24.07.2019
comment
@JasonBunting Конечно, модные словечки сами по себе бесполезны, но различать более общие и конкретные версии концепции относительно нормально. Мы говорим «объект», «машина», «автомобиль», «автомобиль», «седан» и «Хонда-цивик», все из которых являются частными случаями первого. Когда кто-то говорит о программировании управления событиями, это должно вызывать у вас в голове концептуальные образы, отличные от реактивного программирования, если вы знакомы с обоими терминами. - person Frank Bryce; 24.07.2019
comment
@FrankBryce - я согласен, я просто скулю на склонность к новым модным словечкам. В то время как Honda Civic может иметь уникальные функции, которых могут не иметь другие экземпляры седанов, реактивное программирование, по-видимому, не имеет никаких уникальных особенностей по сравнению с программированием, управляемым событиями, за исключением аккуратного нового модного слова; вряд ли приятная особенность, если вы спросите меня. Такие модные словечки только мешают разговору, который в противном случае мог бы иметь ясность. Я полагаю, этого и следовало ожидать, разговаривая с теми, кто не знает устоявшегося разговорного языка. - person Jason Bunting; 25.07.2019
comment
Хороший ответ, но я бы (согласно вашему описанию) утверждал, что программирование событий - это особый случай реактивного программирования. Потому что в реактивном мы говорим: данные изменились независимо от изменения и независимо от того, какая часть данных изменилась, с другой стороны, в событийном программировании нас больше интересуют детали, например Имя изменилось, а Адрес изменился. изменились - это две разные вещи. Также я бы сказал, что событие является особым типом данных. - person adnanmuttaleb; 04.12.2019

Разница в основном связана с тем, как вы "настраиваете" (или объявляете) условность вещей: что происходит с чем-то, когда происходит что-то другое.

В реактивном программировании вы объявляете реакцию на изменение. Вам не нужно заранее предвидеть реакцию, необходимую для этого изменения, вы можете добавить - объявить - эту реакцию в любое время позже. Поэтому ее можно рассматривать как стратегию «вытягивания» или «наблюдания».

Таким образом, в реактивном программировании вы подключаетесь к / отслеживаете данные, которые, как вы знаете, существуют. Данные здесь имеют решающее значение.

Пример: пользователь щелкнул элемент на странице -> обновить счетчик количества кликов, сделанных пользователем.

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

В программировании, управляемом событиями, вы запускаете событие в определенной ситуации в императивно написанном коде. Здесь вам нужно быть явным заранее, потому что событие должно быть инициировано первым, чтобы быть полученным позже, потому что в основном вы отправляете событие в часть кода, где происходит изменение. Итак, это стратегия «толкания».

Таким образом, в программировании, управляемом событиями, вы отправляете событие в определенной ситуации, которое возможно было бы получено некоторые другие части кода. Здесь важна ситуация, данные не имеют значения.

Пример: кто-то посетил страницу контактов -> инициировать событие (которое может вообще не быть получено ни одним слушателем, что является типичным случаем для многих модулей и библиотек).

Пример приложения-калькулятора: дисплей калькулятора — это просто слушатель, а кнопки запускают события. Кнопки должны знать, что они существуют в определенном контексте (но, благодаря шаблону прослушивателя событий, им не обязательно знать, что это за контекст), и поэтому они должны запускать мероприятие.

Так что в большинстве случаев это просто разные условности. Посмотрите на этот простой пример. Пример императивного подхода:

event: perform some operation on a, e.g. a += value, and trigger the event
listener: counter++

И пример реактивного декларативного подхода:

counter: whenever an operation on a occurs, react with this: counter++

В последнем примере не нужно ничего запускать — вы просто «подключаетесь» с реакцией на все, что может произойти.

Таким образом, вы можете сказать, что реакция связана с a в реактивном подходе, в то время как в императивном подходе, управляемом событиями, вы отправляете событие, которое позже может быть получено слушателем, и, поскольку этот тип подхода никаким образом не связан с данными , вы можете изменить это: a += value на любое другое позже, даже полностью удалив a. Подход, основанный на событиях, по существу не имеет ничего общего с данными.

Итак, как вы видите, реактивное программирование ориентировано на данные (изменение данных реагирует на срабатывание другого кода), тогда как программирование, управляемое событиями, ориентировано на процесс (не имеет значения, изменяются ли данные и какие, если они вообще есть — вы просто запускаете событие, которое будет получено некоторыми другими частями кода). В последнем случае вам нужно знать, что это «информирование» других частей кода требуется, и вы должны затем предвидеть, что событие должно быть вызвано. В первом случае вам не нужно этого делать, вы можете сделать это в любое время или вообще не делать - никаких инициирующих событий не требуется - но хитрость здесь в том, что должно быть "что-то", к чему вы можете подключиться. объявление вашей реакции, своего рода наблюдатели, которые позволяют вам реагировать на наблюдаемые изменения.

person forsberg    schedule 21.05.2020

Реактивное программирование — это все о потоках, это могут быть потоки событий или что-то еще. Именно при издании/объявлении этих потоков или подписке/просмотре этих потоков или преобразований потоков, которые приводят к некоторым событиям. Таким образом, обе парадигмы программирования связаны.

person Krishna Ganeriwal    schedule 08.12.2017

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

Реактивное программирование — это парадигма программирования, которая применяется, когда нужно достичь функциональности, похожей на привязку данных в таких библиотеках, как KnockoutJS. Также примером могут служить формулы Excel: все ячейки подобны переменным в памяти. Есть те, которые просто содержат некоторые данные, и те, которые вычисляются на основе этих данных. Если первое меняется, то меняется и второе. Обратите внимание, что парадигма касается реализации более низкого уровня; когда кто-то говорит о реактивном программировании, он имеет в виду данные, их изменения и то, что происходит, когда они мутируют.

С другой стороны, программирование, управляемое событиями, связано с архитектурой системы. В соответствии с этой парадигмой события и обработчики событий являются основой системы, и все строится на них и вокруг них. Типичными примерами могут быть мультиплексирование пользовательского интерфейса и веб-сервера. Вы чувствуете, как все это отличается? Парадигма применяется на уровне целой системы или подсистемы.

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

Promise — это инструмент для достижения параллелизма и определенного порядка выполнения. Его можно использовать в любой парадигме.

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

person Orif Khodjaev    schedule 28.12.2015
comment
программирование, управляемое событиями, связано с системной архитектурой — кто сказал? Вы пытаетесь сделать из яблока апельсин. КАЖДОЕ изменение можно считать событием. Изменения пользовательского интерфейса — это по-прежнему изменения данных. Мультиплексирование веб-сервера (что бы это ни было), по-прежнему состоит из изменений данных. Каждое событие в этом мире — это изменение данных, и наоборот, если вы решите посмотреть на это таким образом. И в этом суть работы разработчика: ваш, надеюсь, высокоточный взгляд на проблемную область во многом определяет, какой подход имеет смысл. - person Jason Bunting; 24.07.2019