Pull to refresh

Comments 6

Когда мне нужно было организовать асинхронную работу с плагином и определённым порядком выполнения и кешированием некоторых результятов я пошёл по другому пути — «суб-модули» знают только о зависимостях для выполнения своих целях, и только после того как они будут удовлетворены произойдёт запрашиваемое действие.

Например пользователь хочет получить какую-то информацию от плагина. Для этого ему нужно авторизоваться. А для того что бы авторизоваться ему нужна открытая сессия с плагином. А что бы была сессия — нужен инстанс плагина.
Немного backbone-style кода
  checkPrerequisites : function(required){//required - массив с именами функций, которые требуется выполнить
            var res = new $.Deferred(),
                tempArr = required.map(function(){return new $.Deferred();});
            _.each(tempArr, function(val, i){
                if(this.get(required[i])){ //Если метод уже был выполнен(установлен в true)
                    val.resolve();
                }else{//в другом случае ждать пока метод будет выполнен
                    this.once('change:'+required[i], function(){
                        var method = this.get(required[i]) ? 'resolve' : 'reject';
                        val[method]();
                    });
                    this[required[i]]();
                }
            }, this);
            $.when.apply($, tempArr).done(function(){
                res.resolve();
            }).fail(function(){
                res.reject();
            });
            return res;
        }

/*Пример вызова*/
this.checkPrerequisites(['selectKey']).done(function(){
  //Сделать чё-то полезное
}.bind(this))



Таким образом можно сделать как асинхронное-паралельное выполнение функций, так и асинхронно-последовательное. Кэширование организовано по флагу выполнения фунции, флаг именуется так же как и называется функция.
Так же требуется определённая организация кода внутри функции — она должна сообщать как она исполнилась и с каким результатом. Пока что есть небольшие неувязки, но в целом меня устраивает т.к позволяет довольно гибко дополнять или пошагово выполнять необходимый функционал.
Какие преимущества по сравнению с rx библиотеками?

P.S. Примеры выглядят ужасно нечитаемо. Это не production-style код.

Структурировать лучше в виде:

var step1 =…
var step2 =…
var errHandlerStep2 =…

root_as
.add(step1)
.add(step2, errHandlerStep2)

И тогда можно сразу увидеть структуру кода. Это избавит от чтения всего месива, чтобы понять что и почему.
Концентрация идёт на бизнес-логику, а не «тактические» подходы как подождать и обработать внешнее событие. Скажем так, другая крайность.

1. Исходную синхронную бизнес-логику можно сравнивать практически diff'ом, игнорируя отступы, после конвертации
2. AsyncSteps объект задаёт своего рода задачу — а-ля асинхронный поток обработки.
2.1. Без лишних проблем можно гарантированно ограничить общее время исполнение шага и всех вложенных шагов просто вызвав as.setTimeout()
2.2. При надобности всю задачу можно аннулировать, не беспокоясь о проблемах освобождения внешних ресурсов, т.к. каждый шаг позволяет установить обработчик отмены
3. Есть возможность хранить переменные состояния. Пример: при получении запроса, можно сохранить всю мета-информацию о нём для дальнейшего использования (отладка, авторизация, логирование т.п.)

Разумеется, основное применение всё же на стороне сервисов, а не в пользовательском интерфейсе. При этом, ни что не мешает использовать тот же Reactive вместе с AsyncSteps (пример внешнего события).

P.S. Я ни в коем случае вас не порицаю, если вам удобнее писать что-то вроде:

function do_try(){
    call_library();
}

function do_catch( err ){
    // handle error
}

try {
    do_try();
} catch( e ) {
    do_catch( e );
}
У меня такое впечатление, что пока никто не задавался вопросом как серьёзную бизнес-логику, вроде финансовых транзакций реального времени перенести на асинхронные рельсы.
Либо кто-то об этом задумывался, но разобравшись в проблеме и осознав сколько граблей можно собрать, просто забыл эту идея как страшный сон.
Расскажите, какие есть слабые места в существующих тактических решениях и как ваше решение поможет их обойти.
При первом приближении кажется, что это вариация Async.js.
Я не берусь быть истиной в последней инстанции, но большинство из существующих подходов:
  • узкоспециализированы и наполнены специфичным программным интерфейсов определённой среды исполнения
  • и/или скудны на обработку ошибок исполнения и инструменты отладки
  • и/или в принципе, могут отразить лишь определённеый кусок кода, больше ориентированы прятать громоздкую логику под капот
  • и/или в принципе, не предусмотрено понятие ограничения по времени и отмены задачи
  • и/или отсутствие какого-то централизованного представления о задаче — всё размазано по локальным переменным
  • и/или слабо контролируют правильность использование инструмента
  • и/или не представляют концепции написания интерфейса библиотек, которые внутри задают собственные шаги выполнения


Моей целью было сделать инструмент, с помощью которого можно в буквально смысле перенести «синхронный» (последовательный) код в асинхронную среду исполнения.

Возьмём типовой пример бизнес логики:
Создаётся рабочий поток (worker thread), который в цикле обрабатывает поступающие запросы:
1. Устанавливается общее ограничение по времени на обработку одного запроса
2. Обрабатываются входные данные
3. Происходят вызовы в другие системы, каждый со своим ограничением по времени
4. Происходят сравнительно тривиальные вычисления (сложные подразумевают оформление в виде библиотеки со всем вытекающим из этого)
5. Формируются и отсылаются выходные данные

Альтернативно 1:
* Кидается исключение, которое не перехватывается бизнес-логикой
* Освобождаются все ресурсы, связанные с данным запросом
* Ловится исключение и формируется ответ-ошибка

Альтернативно 2:
* Срабатывает ограничение по времени исполнения
* Задача отменяется
* Освобождаются все ресурсы
* Формируется ответ-ошибка


FutoIn AsyncSteps именно и был реализовано как аналогия рабочего потока (точнее даже «лёгкого» потока), который можно реализовать на широко распространённых языках программирования.

Хочу ещё раз отметить, что AsyncSteps — это не самоцель, а концепция решения проблемы написания унифицированного по структуре кода бизнес-логики на разных языках программирования.
Проблема ставится другой концепцией, которая решается в рамках другого проекта: как написать легко масштабируемое асинхронное приложение с повторно используемым кодом, чётко оформленным в компоненты, используя разные технологии разработки. Пример: сначала написать прототип на JavaScript/Python, а потом только отдельные части оптимизировать/сделать более надёжными/развить на Java, C++ или C# без шаманства с «кодом-клеем» или вообще переписыванием уже отлаженных компонентов.
Sign up to leave a comment.

Articles