Статьи

Связь в реальном времени в AngularJS с ($ Q) orlate

Этот пост знакомит с легкой  ($ Q)  библиотекой орлатов .

Популярный тип взаимодействия, для   которого нанят iVision, — это оценка архитектуры. Для проектов по оценке мы анализируем существующую систему, сопоставляем наш собственный опыт, отраслевые стандарты и лучшие практики с тем, что мы находим, затем предоставляем обратную связь и потенциальную дорожную карту для итерации к желаемому решению. Я принимал участие во всем: от комплексного анализа всего технологического стека с партнерами из нашего центра обработки данных, конвергентных сетей и практики инфраструктуры, чтобы предоставить план бизнеса / ИТ для обеспечения готовности к облачным вычислениям, до целенаправленного анализа реализаций AngularJS.

Недавно я работал с заказчиком, который создал очень зрелое доказательство концепции с использованием Angular в системе, в которой было то, что я называю «отключенными асинхронными процессами». Это процессы, которые действительно «запускаются и забываются», потому что сообщение проходит через очереди сообщений и рабочие процессы до того, как ответ генерируется по другому каналу. Хотя мой первый шаг всегда заключается в том, чтобы бросить вызов архитектуре такого типа (иногда она реализуется с уверенностью, что она автоматически быстрее или более масштабируема, когда есть другие подходы, которые могут достичь тех же результатов с меньшей сложностью), в этом случае это действительно выглядело как правильная архитектура, необходимая для этой системы.

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

1. ЗАПРЕЩЕННЫЕ ЗАПРОСЫ

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

Есть несколько способов справиться с этим в Angular. Одним из них является создание обещания на маршруте, что приведет к задержке загрузки представления, пока обещание не будет выполнено. Это не вариант, если вы не используете маршруты, а иногда ваши службы могут не относиться к конкретному маршруту. Другой механизм — просто вернуть общее  обещание . Можно зарегистрировать несколько обратных вызовов, поэтому, если служба отслеживает одно обещание, она может продолжать предоставлять его, и даже если это было разрешено в прошлом, обещание будет выполнено.

Чтобы понять, что я имею в виду, взгляните на  этот jsfiddle . Обратите внимание, что второй вызов происходит спустя много времени после того, как список уже заполнен, но обещание все еще срабатывает и заполняет второй список (список заполняется через 1 секунду, а второе обещание запрашивается через 2 секунды). Одно и то же обещание всегда возвращается.

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

cachedrequests

Чтобы улучшить этот сценарий, ($ Q) orlate предоставляет возможность отслеживать несколько запросов с таймаутами. Если таймаут не является проблемой или обрабатывается локально, достаточно простого использования  $ q  . Что делает ($ Q) orlate, так это предоставляет механизм автоматического тайм-аута и истечения срока действия запроса, поэтому он отслеживает несколько запросов, даже если вы выполняете их одним вызовом.

При вызове ($ Q) orlate передается идентификатор, который однозначно определяет корреляцию (он будет сгенерирован для вас, если вы не передадите его). В  этом примере  тайм-аут используется для эмуляции отложенного ответа. Обратите внимание, что разрешение имеет дополнительный параметр для корреляции.

$timeout(function () {
    _this.list = [1, 2, 3, 4, 5];
    _this.qorlate.resolve(_this.id, _this.list);                     
}, qorlate.defaultTimeout + 100);

Сервис всегда возвращает корреляцию. Это связано с тем, что qorlate немедленно вернет последнее обещание, которое было разрешено или отклонено, поэтому любые значения (успех или ошибка) будут удовлетворены в обещании.

return this.qorlate({ id: this.id }).promise;

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

Хотя это один из вариантов использования, ($ Q) orlate больше подходит для двух других сценариев.

2. ДИСКРЕТНЫЕ ОТКЛЮЧЕННЫЕ СООБЩЕНИЯ

Я целенаправленно использую метку «отключен» вместо «асинхронный», поскольку прямой вызов AJAX может быть асинхронным, хотя он все еще «подключен», в том смысле, что существует прямой путь от вызова до разрешения обещания. Что менее ясно, так это когда сообщение отправляется на обработку, а затем возвращается через другой канал, например, через веб-сокет. Верхняя часть следующего рисунка демонстрирует это:

CorrelatedRequests

Я называю это коррелированным событием, потому что, хотя событие возврата отображается независимо от запроса (т. Е. Через соединение через веб-сокеты), оно коррелируется с первоначальным запросом. Например, у вас может быть форма, которая отправляется в систему очередей, проверяется обработчиком на бэкэнде, а затем ответ направляется обратно. В этих случаях вы все еще хотите отслеживать сообщение (т. Е. Если время ожидания истекло, возможно, это полезно сообщить пользователю), но API может быть не совсем понятным. Рассмотрим что-то подобное, к чему вы можете привыкнуть:

var id = 1;
function sendRequest() {
    service.on('response', function (response) {
        if (response.id === id) {
            // do something
            // and don't forget to unregister
        }
    }
    service.send(id, request);
}

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

Одна из приятных сторон спецификации обещаний состоит в том, что она помогает сделать код чище и легче читать. Что если бы вы могли сделать что-то вроде этого вместо этого:

service.request(id, request).
    then(function success(response) {
        // yes!
    }, function error(err) {
        // nope!
    });

Это прямое обещание. Возможно ли это, даже когда механизмы отключены? Ответ: «Да». Сервис просто должен установить обещание с корреляцией:

var correlation = this.qorlate();
return correlation.promise;

Когда приходит сообщение, корреляция уведомляется:

this.qorlate.resolve(correlation.id, response);

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

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

3. Агрегатор событий или паб / саб

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

Подписка выглядит так:

var cancel = q({subscribe:'addItem'}).always(function (item) {
    rs.list.push(item);
});

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

Вызов ($ Q) orlate вернет функцию для отмены подписки — это так же просто, как вызвать cancel (); и вы отписались. API для создания события ничем не отличается:

q.resolve('addItem', (new Date()).getTime());

Фактически, как вы можете видеть из  тестовых спецификаций , вы можете перегружать один и тот же идентификатор обещаниями  и  подписками. Модуль довольно легкий. Это:

  • Создает обещание при вызове функции
  • Устанавливает таймер для отклонения обещания, если истекло время ожидания (это настраивается на уровне поставщика и отдельного вызова)
  • Отслеживает обещания, поэтому, когда корреляция решена или отклонена, она может уведомить всех потребителей
  • Создает новый набор обещаний для повторяющихся подписок

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

Вы можете просматривать исходный код, предлагать отзывы, генерировать запросы на извлечение, читать полную документацию, запускать тесты и читать примеры в Интернете по адресу  https://github.com/jeremylikness/qorlate . Наслаждайтесь!