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

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

Все ваши проблемы от того, что у вас нет разделения приложения на Model и View. Я так понял у вас вьюшки ходят на сервер за данными и отсюда все траблы.

Случай 1. Доступ к disposed-объектам

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

Случай 2. Usability

Блокировка приложения модальным окном «подождите, мы за вами не поспеваем» — это не юзабилити, а чёрт знает что. Для некритических даных достаточно фоновой синхронизации. Для критических — блокировать только виджеты, которым необходимо актуальное состояние этих данных.

Случай 3. Двойные вызовы к сервисам

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

Случай 4. О кэшировании данных

Опять же, при работе через модель, кэширование получается автоматом. Опционально можно добавить инвалидацию по времени, но лучше всё же сделать серверные нотификации об изменениях.

Случай 5. Об обработке ошибок

Опять же, странное какое-то юзабилити. Зачем пользователю пренепременно выбирать «агента» для просмотра информации? Вы и так знаете всех его «агентов» и можете определить имеет он доступ к ней или нет и сразу показать информацию, если хотябы через одного из агентов он доступ имеет.
Добрый вечер.
По первым четырем случаям вы описали ровно так, как у нас сделано.
По пятому случаю — речь именно о ситуации когда надо выбрать одно из нескольких.
НЛО прилетело и опубликовало эту надпись здесь
Добрый день.
Ценное замечание, спасибо. В первой ссылке в статье про это говорится, поэтому тут написать поленились. Но вообще да, стоило.
НЛО прилетело и опубликовало эту надпись здесь
> возможна ситуация, когда со страницы на сервер шлется запрос, и пользователь внезапно покидает страницу (например, он ткнул не тот пункт меню). View model текущего окна проходит конвеер dispose, пользователь уходит на другую страницу.
> И тут с сервера возвращается результат запроса.

Почему просто не прерывать запрос?
Это http, ответ будет в «любом» случае.
А поскольку… хм… ну другие уже сказали почему, то решают вот так вот с обратной стороны.

> А поскольку… хм… ну другие уже сказали почему

А именно?
Отвечу в личку
А как вот сказать promise по-русски? Я думаю, «посул».
Мне кажется, вас спасали не промисы, а то, что вы вовремя написали единый интерфес через который общались с сервером ;)

И да, против них самих я ничего не имею, всеми руками за.
Добрый день.
Спасло, по сути, и то и другое. Если бы вместо promise-ов использовали callbacks, то код получился бы куда более лохматым. Если бы вообще получился.
Когда мы писали приложение, описанное в нашей предыдущей статье, то реализовали его как SPA. Соответственно, пришлось очень плотно поработать над очисткой памяти, и буквально всё имело конвеер dispose. При этом, возможна ситуация, когда со страницы на сервер шлется запрос, и пользователь внезапно покидает страницу (например, он ткнул не тот пункт меню). View model текущего окна проходит конвеер dispose, пользователь уходит на другую страницу.
И тут с сервера возвращается результат запроса.
Говорить о том, что может случиться в такой ситуации, бессмысленно – случиться может всё, что угодно. Лучшее, что происходило — летела ошибка, и становилось понятно, что что-то не так.


Как-то хреновенько приложение спроектировано. В такой ситуации в лучшем случае должно быть изменение локально объявленных переменных, которые прибиваются garbage collector-ом после колбэка.

Случай 3. Двойные вызовы к сервисам

Проблема:

У нас возникла ситуация, когда несколько объектов на странице могут попросить одни и те же данные. Ходить на сервер за одними и теми же данными не хочется (как и показывать одинаковые статусы по типу описанных выше). Попробуем что-нибудь придумать.


Вы это. Инвалидацию кэша придумайте лучше. А данные хорошо бы хранить все-таки в модельке или сторадже каком-нибудь.

Не, в целом был бы это пост из песочницы — было бы круто.
Но вот для корпоративного блога, в котором пишут
Основу штата составляют высококлассные специалисты в технологиях Microsoft, Java, Mobile (iOS, Android, Windows Phone, Titanium), MicroStrategy, SAS.

немножко страшно становится.
В такой ситуации в лучшем случае должно быть изменение локально объявленных переменных, которые прибиваются garbage collector-ом после колбэка.
Пример 1:
Callback создает объект, в котором есть knockout computed. Они являются предметом утечки памяти, и у них нужно вызывать dispose. Его уже никто не вызовет, потому что метод dispose объекта, который должен был это сделать уже был вызван.

Пример 2:
Подписка на кастомные события (например, durandal events). Отписываться нужно явным образом. Делается это в dispose, который уже был вызван. Утечка памяти еще ладно, коллбэки подписки будут вызываться.

Пример 3:
Банальное выставление в null свойств объекта при dispose и попытка к ним обратиться в callback-е ведет к ошибке.

Вы это. Инвалидацию кэша придумайте лучше. А данные хорошо бы хранить все-таки в модельке или сторадже каком-нибудь.
Кэширование данных, и одновременные вызовы одного и того же сервиса это две разные проблемы. И потому они описаны в статье двумя разными пунктами. Данные, собственно, в storage и хранятся.
При написании комментариев почему-то все теги слетают, в том числе ссылки.
В общем, при необходимости легко гуглится как knockout computeds так и Durandal events.
Но лучше всё же атомы :-)
Подписка на кастомные события (например, durandal events). Отписываться нужно явным образом. Делается это в dispose, который уже был вызван. Утечка памяти еще ладно, коллбэки подписки будут вызываться.


Durandul это я так понимаю это message broker.
Какие тогда коллбэки подписки? Вы о чем?
Нормальный сценарий:
1. Объект создается.
2. Объект делает вызов к сервису.
3. Приходит ответ от сервиса, после чего объект подписывается на некое событие
4. Вызов dispose — объект отписывается от события.

Случай, рассматриваемый в статье:
1. Объект создается.
2. Объект делает вызов к сервису.
3. Вызов dispose.
4. Приходит ответ от сервиса. Объект подписывается на некое событие. Подписка никем уже не будет почищена, объект завис в памяти, обработчик события вызывается на уничтоженном объекте.
Нормальный сценарий это нормальный routing. Вместе с подписками и отписками. Если вызов сделали, а он уже отписался то ответ будет отправлен в /dev/null. Вот и все.
Почему при вызове dispose не вызывается dispose у обещания?
Метод dispose во втором листинге кода в статье это и делает — вызывает abort-ы у выполняющихся запросов.
По идее он должен вызывать аборты у принадлежащих ему объектов, независимо от их природы. Например, как вы будете абортить setTimeout-ы? Создадите отдельную коллекцию таймаутов?
Я, признаться честно, соль вопроса не понимаю.
Хранить объекты в одной приватной коллекции или в двух — внутренняя кухня объекта и, в конечном счете, дело вкуса разработчика, как это реализовать. В чем тут вопрос?
В том, чтобы не городить костыли с копипастой для каждого случая, а сделать обобщённое решение.
Описываемый модуль и является обобщенным решением — он базовый для всех сервисов в приложении и вообще все вызовы идут через него.
Будет он в один цикл перебирать массив, вызывать либо abort для deferreds либо clearTimeout для эмуляций асинхронности на случай кэша — шесть строчек кода, написанного единожды.
Будет перебирать два массива, и для каждого звать свое — те же шесть строчек кода, написанного единожды.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий