Кэширование URL-адреса/состояния с параметрами
Я делаю мобильное приложение с помощью Cordova и AngularJS. В настоящее время я установил ui-router для маршрутизации, но я открыт для любой другой альтернативы для маршрутизации.
Мое желание: я хочу кэшировать определенные представления, связанные с параметрами. Другими словами, я хочу кэшировать пути (или страницы).
Пример ситуации: скажем, что мы видим страницу на панели инструментов, щелкните по обложке книги, которая перенаправляет на путь book/2
. Этот путь загружается в первый раз в приложение. Маршрутизатор перенаправляет от HomeController
до BooksController
(независимо от имени). Теперь BooksController
загружает данные для данного $stateParams
(book id = 2) и создает представление, заполненное информацией о выбранной книге.
Что я хочу в этой ситуации:
- Я возвращаюсь на страницу панели мониторинга - он уже загружен (кэширован?)
- Я снова выбираю книгу # 2
- Контроллер или маршрутизатор уведомляет, что данные об этой книге уже загружены.
- Вид не воссоздается, вместо этого он извлекается из кеша
На самом деле было бы лучше всего кэшировать все, что я посещаю, основываясь на пути. Предварительная загрузка также будет прохладной.
Причина: производительность. Когда я открываю список книг, я хочу, чтобы он показывался быстро. Когда просмотр создается каждый раз, анимация изменения страницы выглядит ужасно (она негладкая).
Любая помощь будет оценена.
EDIT:
Прежде всего, поскольку я считаю, что это распространенная проблема для многих мобильных программистов для HTML-приложений, я хотел бы уточнить некоторые данные:
- Я не ищу хаки, но ясное решение, если это возможно.
- Данные в представлениях используют AngularJS, поэтому ДА, есть такие вещи, как
ng-bind
, ng-repeat
и т.д.
- Кэширование необходимо для данных и элементов DOM. Насколько я знаю, работа с макетом браузера не так дорого, как воссоздание всего дерева DOM. И перерисовать не то, что мы можем опустить.
- Наличие отдельных контроллеров - это естественная вещь. Поскольку я мог уйти без него, я не могу представить, как это все равно будет работать.
У меня есть некоторые полурешения, но я буду строго соблюдать свое желание.
Решение 1.
Поместите все представления в один файл (я могу сделать это с помощью конструктора gulp) и используйте ng-show
. Это самое простое решение, и я не верю, что кто-то, кто знает AngularJS, не подумает об этом.
A хороший трюк (от @DmitriZaitsev) - создать вспомогательную функцию для отображения/скрытия элемента на основе текущего пути местоположения.
Преимущества:
- Это легко.
- Вставка функции предварительной загрузки.
Недостатки:
- все представления должны быть в одном файле. Не спрашивайте, почему это не удобно.
- Поскольку все это касается мобильных устройств, иногда я хочу "очистить" память. Единственный способ, который я могу придумать, - удалить этих детей из DOM. Грязный, но нормально.
- Я не могу легко кэшировать/книгу/2 и /book/ 3 одновременно. Мне пришлось бы динамически создавать DOM файлы поверх некоторых шаблонов для каждого представления, связанного с параметрами.
Решение 2.
Используйте липкие состояния и будущие состояния от ui-router-extras, что является удивительным.
Преимущества:
- Разделенные виды.
- Очень простое использование, очень простое, поскольку это просто плагин для
ui-router
.
- Может создавать динамические подстанции. Таким образом, можно было бы кэшировать
book1
, book2
, но я не уверен в book/1
и book/2
Недостатки:
- Опять же, я не уверен, но я не нашел пример с кешированием пары /tuple
(view, parameters)
. Кроме этого это выглядит круто.
Ответы
Ответ 1
Это именно та проблема, которую мне пришлось решить для моего сайта 33hotels.com. Вы можете проверить его и сыграть с вкладками "Фильтр" и "Список фильтров" (соответствующие различным маршрутам) и увидеть, что представление обновляется мгновенно без задержки!
Как я это сделал? Идея удивительно проста - избавиться от маршрутизатора!
Почему? Поскольку способ работы маршрутизатора - это перекомпилировать представление каждого изменения маршрута. Да, Angular кэширует шаблон, но не скомпилированный вид, заполненный данными. Даже если данные не меняются! В результате, когда я использовал Router в прошлом, коммутатор всегда чувствовал себя вялым и нереактивным. Каждый раз, когда я мог заметить раздражающую задержку, это была небольшая часть секунды, но все же заметно.
Теперь решение, которое я использовал? Не перекомпилируйте свои представления! Храните их внутри DOM в любое время! Затем используйте ng-hide
/ng-show
, чтобы скрыть/показать их в зависимости от маршрутов:
<div ng-show="routeIs('/dashboard')">
<-- Your template for Dashboard -->
</div>
<div ng-show="routeIs('/book')">
<-- Your template for Book -->
</div>
Затем создайте функцию routeIs(string)
внутри Controller
, чтобы проверить, соответствует ли $location.path()
string
, или начинается с string
, когда я его использую. Таким образом, я все еще получаю свой вид для всех патчей, например /book/2
. Вот функция, которую я использую:
$scope.routeBegins = function () {
return _.some(arguments, function (string) {
return 0 === $location.path().indexOf(string);
});
};
Так что не нужно быть умным с кешированием - просто держите его в DOM. Он будет кэшировать ваши представления для вас!
И самое лучшее - когда ваши данные будут изменены, Angular мгновенно обновит все Представления внутри вашей DOM, даже скрытые!
Почему это потрясающе? Потому что, как пользователь, мне не нужно ждать полного разбора и компиляции в тот момент, когда я хочу увидеть результат. Я хочу щелкнуть вкладку и сразу увидеть мои результаты! Почему сайт должен ждать, пока я нажму на него, и , а затем начнет повторную компиляцию, поскольку я жду? Особенно, когда это было легко сделать до этого, во время моего компьютера не работает.
Есть ли недостатки? Единственным реальным, о котором я могу думать, является загрузка памяти с большим количеством элементов DOM. Однако этот фактический размер байтов моих представлений пренебрежимо мал, сравнивая, например, со всеми JS, CSS и изображениями.
Другим возможным, но недопустимым недостатком является стоимость перекомпиляции скрытых просмотров. Здесь вы можете стать умнее и избегать вычислений тяжелых частей в зависимости от текущих маршрутов.
Кроме того, вы не перекомпилируете весь View, а только части, подверженные изменениям данных, что также снижает вычислительные затраты.
Я считаю весьма примечательным, что все используют Маршруты и, похоже, совершенно не знают (или не знают) об этой проблеме.
Ответ 2
1) О статических страницах в приложении (представления), angular берет на себя загрузку.
например: для страницы вашей панели мониторинга вам не нужно беспокоиться о кешировании страницы, так как angular позаботится об этом. angular будет загружать только представление панели мониторинга один раз и во всех последующих запросах для представления панели мониторинга, angular просто покажет вам представление (не загружает файл для просмотра), если это все статический вид без каких-либо данных, загруженных ajax calls.
2), если ваша панель сама загружает список книг (или аналогичные данные) через ajax, то вы можете сообщить своему контроллеру только один раз загрузить данные и сохранить их в localstorage, а при последующих запросах на страницу панели мониторинга можно загрузить только данные из localStorage.
3) аналогичный подход можно использовать, когда ваш BooksController
загружает данные в представление. Вы можете проверить свой BookController, если запрос для конкретной книги был ранее сделан, и если вы не можете сохранить его в localstorage или в базе данных. и если данные были запрошены ранее, вы можете загрузить те же данные из хранилища без запроса на сервер.
Пример ситуации:
скажем, пользователь делает запрос для book1, затем
- ваш контроллер i.e BooksController проверяет, были ли ранее запрошены те же данные,
- Если нет, вы можете загрузить данные через вызов ajax с сервера, а также сохранить его в локальном хранилище.
- если он был загружен, прежде чем вы загрузите данные, хранящиеся в localstorage или в базе данных.
Ответ 3
Если вы используете ui.router, тогда вы должны взглянуть на дополнительные функции ui.router, в частности на модуль липких состояний. Это позволяет вам кэшировать "дерево" состояния (включая визуализированные представления), поэтому их не нужно компилировать или повторно отображать при изменениях состояния.
http://christopherthielen.github.io/ui-router-extras/
Вот демо:
http://christopherthielen.github.io/ui-router-extras/example/sticky/#/