Статьи

Функциональное реактивное программирование и JavaScript

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

Пример

Давайте рассмотрим пример, чтобы увидеть, как FRP может решить проблему, с которой вам, вероятно, приходилось сталкиваться в JavaScript раньше — когда асинхронные запросы к серверу не возвращаются в том порядке, в котором они были запрошены. Для демонстрации, скажем, у нас есть требование каскадного раскрывающегося списка, который состоит из двух связанных раскрывающихся списков. Когда вы выбираете значение из первого, выдается запрос AJAX, чтобы получить список значений для заполнения второго раскрывающегося списка. Вы можете реализовать в jQuery (или любой другой платформе JavaScript) что-то вроде этого:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<script>// <![CDATA[
  $('#dropdown1')change(function () {
    var selected = $(this).val();
 
    var promise = $.ajax('/path/to/your/server', {
        data: {value: selected}
    });
 
    promise.then(function(data){
        var html = $.map(data, function(item){
            return '<option value="' + item + '">' + item + '</option>'
        }).join('');
        $('#dropdown2').html(html);
    });
  });
// ]]></script>

Проблема возникает, когда пользователь быстро выбирает другие значения из раскрывающегося списка1, и ответы не в порядке, в котором они были запрошены. Вы могли бы в конечном итоге иметь недопустимые значения в dropdown2. Одним из способов решения этой проблемы является отключение dropdown1 до тех пор, пока ответ не вернется, чтобы пользователь не мог выбрать другие значения. К сожалению, это делает приложение менее отзывчивым, поскольку пользователь не может взаимодействовать с вводом dropdown1. Именно тогда FRP дает вам представление — что если вы можете сделать эти ответы видимыми , например поток событий , где вы хотите, чтобы он реагировал только на самый последний ответ в потоке. Существует две популярные библиотеки JavaScript FRP: Bacon.js и Rx.js. Я буду использовать Rx.js в этом примере. Идея состоит в том, чтобы выдвинуть эти обещания ответа, как только вы включите их в наблюдаемый поток событий. Библиотека развернет эти обещания, как только они будут преобразованы в еще один поток, где будет наблюдать наше приложение. Он будет реагировать только на последнее событие. Rx.js не имеет встроенной шины событий, в которую можно вставлять значения и наблюдать. (В отличие от Bacon.js, где у вас есть класс Bus, который может это сделать). Однако вы можете с легкостью создать собственную шину событий или найти такую, которая уже реализована, как эта . С помощью библиотеки наш код выглядит невероятно простым:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>// <![CDATA[
var bus = new MessageQueue();
 
  $('#dropdown1').change(function () {
    var selected = $(this).val();
 
    var promise = $.ajax('/path/to/your/server', {
        data: {value: selected}
    });
 
    bus.push(promise);
  });
 
  bus.flatMapLatest(function(promise){
    return Rx.Observable.fromPromise(promise)
  }).subscribe(function(data){
    var html = $.map(data, function(item){
        return '<option value="' + item + '">' + item + '</option>'
    }).join('');
    $('#dropdown2').html(html);
  })
// ]]></script>

Сначала мы создаем наблюдаемый поток, называемый шиной, в который мы можем увеличить значение. Затем мы подписываемся на поток, чтобы мы могли реагировать, когда значение (ответ) изменяется. Метод фильтра flatMapLatest — это тот, кто делает всю магию здесь. Что он делает, так это разворачивает обещание, когда оно преобразуется в другой наблюдаемый поток. Но, пока он ожидает выполнения обещания, если последует другое обещание, он переключится на этот поток. Нет необходимости отключать раскрывающийся вход. Пользователь может попытаться выбрать другое значение, если он ошибочно выбрал одно, не ожидая возвращения предыдущего ответа. Второй раскрывающийся список гарантированно синхронизируется.

Последние мысли

Для такого небольшого приложения FRP на самом деле не предлагает больше преимуществ, чем функциональное программирование или программирование процедур. Но по мере того, как система расширяется в таких аспектах, как количество интерактивных компонентов, параллелизм, количество асинхронных операций (и обратных вызовов), парадигма FRP начинает предлагать абстракции, которые помогают разработчикам не беспокоиться о переоценке триггерных выражений, изменяющихся во времени. Я надеюсь, что вы найдете эту статью полезной и достаточно интригующей, чтобы больше узнать о FRP. Наслаждаться.

Ссылка: Функциональное реактивное программирование и JavaScript от нашего партнера JCG Фуонга Нгуена в блоге