Откуда лаги?
Доброго времени суток.
Я чесна не вдупляю откуда лаги, вот обьясните, может алгоритм кривой или что то не учел (все еще бесконечный скроллинг) Кода много, поэтому опишу архитектуру Сервер отдает обьявления заданным числом по запросу. Висит бесконечный скроллинг ionic фреймоврка, и когда доскроливаем до конца делается запрос. 2 директивы 1) watch-ем следит за изменением длинны массива jsono-в обьявлений, каждый раз при срабатывании (пришли данные с сервера) из полученного генерируется html шаблон, компилится ангуляром,вставляется в dom, узнаем его высоту и даем абсолютную позицию и display none. Устанавливаем ему top относительно предыдущего обьявления (высота + позиция). Все, эта директива срабатывает только 1 раз при загрузке обяьвлений и особо не грузит. На выходе из нее получаем два массива в контроллере 1) Все вставленные обьявления (дом элементы) 2) и массив с координатами низа и верха обьявлений ЗЫ тоесть, все обьявления парсятся, добавляются в дом скрытыми, а потом мы уже оперируем только с массивами ссылок на эти элементы и их позициями (которые фиксированы и скрытые элементы лежат там где нужно) 2) директива уже вызывается с завидным постоянством requestanimationframe, следим за скроллингом, если был скролл то вызываем функцию, которой отдаем верхнюю и нижнюю точку экрана. боунд клиент ректом В этой функции мы перебираем массив (его вернула 1 директива) с элементами и проверяем какой из них попадает в зону видимости for advertId of buffer if (top - bufferZone) <= marginBottom[advertId] <= (bottom + bufferZone) or (top - bufferZone) <= marginTop[advertId] <= (bottom + bufferZone) visible.push advertId Отслеживаю верхнюю и нижнюю часть обьявлений попадающих под видимость экрана и буферную зону (чтобы обьявления успевали гененрироваться) Кстати, чтобы не ловить лагов при переборе огромного кол-ва элементов в массиве dom-элементов, я слайсом копирую часть огромного массива, где находится пользователь +- один элемент, в общем перебор ведется не по 200 элементному а по 6. Все видимые айдишники элементов добавляются в массив visible, и запускается функция, которая перебирает этот массив (обычно 2 - 3 элемента) и дает им всем (получае доступ по ид из главного большого массива) display inline. Так же есть массив oldVisible, он хранит айдишники элементов, которые передавались функции в прошлый раз. И нужен для того, чтобы скрывать старые обьявлений в этой же функции, а потом определять положение пользователя в большом массиве элементов. зы я конечно могу замутить оптимизацию, чтобы скроллинг угадывал куда собирается скроллить пользователь. Это не сложно, но не думаю что сильно изменится производительнсоть зы зы Спааасииити погибаю! 2 недели пилю эту хрень уже столько способов перепробовал. Находил вот это http://habrahabr.ru/post/204350/ Но у него работает всего лишь на 400 сотнях, текстовых нод А мне нужно хотя бы на 400 обьявлений с слайдерами (которые автоматом крутятся иногда) и текстом (а лагает и без слайдеров) Да еще и на телефонах :help: |
Покажи исходники и пример того что должно получиться. Хотя бы скрин с того что есть.
Очень интересно скрол растягивает страницу или занимает ограниченное пространство, можно ли скролить строчки целиком или это нужно делать попиксельно. (вероятно попиксельно но мало ли) Строки (вставленные элементы) инфинити скролла имеют фиксированную высоту или переменную. насколько сложные элементы вставляются и в каких циклах в шаблоне. Непонятно как ты и где реагируешь на изменение скрола Очень интересно что происходит с невидимыми слайдерами в частности отключаются ли они после скрытия. |
DjDiablo,
Чуть попозже покажу, сейчас не удобно. Кстати, ангуляр же каждый раз когда происходит событие заного компилит дом, а точнее делает хэш, сравнивает с предыдущим и если отличаются то компилит да? |
Цитата:
|
Я тут поразмышлял на досуге на твоей задачей и запилил с нуля эксперимент. В принципе сейчас в хроме скролятся 40 000 директив с таймерами без каких либо ощутимых проблем
вот что получилось. 1) Во первых я прикинул что если я скрою 20000 элементов какой либо директивой типо ng-show то у меня будет 20 000 watch которые будут наблюдать за тем не изменилось ли значение в ng-show, а это гарантированные тормоза. Такая перспектива меня совсем не улыбала и Я реализовал подход в котором добавляются и компилируются только элементы которые были невидимы но стали видимы после смещения скролла, элементы выходящие за границы видимости удаляются. А те элементы которые были видимы раньше и остались видимы после смещения скролла ни как не изменяются. То есть я минимизировал количество манипуляций с DOM и компиляций выполнив их все вручную отказавшись от использования шаблонизатора. 2) Шага один оказалось недостаточно и на большом количестве элементов появились тормоза. Как выяснилось после удаления остался работать таймер в удаленных директивах (о чем кстатии недвухсмысленно предупреждают в документации). Встал вопрос о том как убить таймер. В итоге каждую директиву я научил определять не вышла ли она за границы видимой зоны и если вышла то останавливать таймер и все watch. Я хотел сделать чтобы при выходе за границы директива еще сама и себя удаляла, но watch в директиве работает с опозданием и директивы при скролинге не успевают удаляться вовремя. Удаление и вставка элементов вероятно является не обязательной и достаточно будет просто чтобы скрытый элемент заглушил таймер и все watch, напротив при появлении в видимой зоне все таймеры и наблюдатели должны ожить. Тобишь функция которая оживит watch и таймеры должна быть запущена infinityScroll'ом но ни как не watche'ром в самой директиве ибо мы опять получим тысячи тормозных watch. Резюмируя результаты эксперимента могу сказать что 1) ключом к успеху является отписывание от событий/таймеров/наблюдений элементов вышедших за пределы видимой зоны. То есть это задача больше вставленной в infinityScroll директивы чем самого infinityScroll. 2) Еще важный момент в том чтобы не допустить в шаблонизаторе десятков тысяч одновременно работающих ng-if/ng-show и т.п. поскольку каждая такая директива использует дорогой $scope.$watch. 3) Следует избегать полной перегенерации dom при небольшом смещении скролла (но это не самый критичный момент) Пощупать опыт можно здесь. для генерации кучи записей кликните на скролл и удерживайте pageDown <iframe width="100%" height="750" src="http://jsfiddle.net/5hAy2/3/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe> В данный момент снижается гладкость скроллинга при очень большом количестве записей. Это связано с перебором массива items целиком но это можно исправить через оптимизацию поиска в массиве items элементов которые должны быть видимы , удаляемые же элементы можно найти просто перебрав кэш. P.S. Код эксперементальный на скорую руку как следствие грязный но надеюсь что этого будет достаточно чтобы понять смысл. P.P.S Потом если будет время то я еще по экспериментирую с шаблонизатором. Думаю если написать умный аналог ng-repeat который возьмет на себя задачу с минимизацией манипуляциями dom то этого будет вполне достаточно чтобы заменить Render и RenderItem шаблонизацией. В принципе на умный ng-repeat можно повесить и задачу информирования удаляемых элементов об их удалении (если не найду другой приемлемый способ(UPD: уже найден)) чтобы те могли остановить таймеры. Вместо удаления также можно попробовать сваять умный ng-repeat заточенный под скрытие элементов вместо удаления и информирующий детей о скрытии и наоборот о появлении что те могли остановить таймер. Нужно еще попробывать запись item in items track by $id(item.id) чото я ее непомню может ее раньше небыло. В общем пока что я пребываю в размышлениях обо всем этом. P.P.P.S пожалуй стоит еще с $scope.$on('$destroy',function(){}); поэксперементировать. (UPD: выбрал element.$on("$destroy",..)) |
Немного переписанный вариант с использованием element.on("$destroy",function(){}); вместо отслеживания директивой выхода за границы видимой области, генерации событий из вне и прочей фигни.
ссылка на fiddle http://jsfiddle.net/5hAy2/6/ |
DjDiablo,
Я тебя люблю... так заботишься :cray: Цитата:
|
nerv_,
Тогда че меня путали мануалы из сети??? Ты хочешь сказать оно хэш не делает? а тупо идет парсить сразу? адддд |
|
Цитата:
про возможные оптимизации есть тема, линк я давал. Т.е. эту тему можно было не создавать, а перечитать тему про оптимизацию. А создавать тему без кода... :) Лаги оттуда) |
Часовой пояс GMT +3, время: 20:55. |