Почему Chrome использует больше CPU, когда скрыт большой элемент Knockout?
У меня одностраничное веб-приложение, которое использует Knockout.js 2.2.1 для отображения потоковой передачи информации с сервера (используя socket.io, хотя я не думаю, что это важно). Это приложение также содержит большую таблицу данных, которая создается из объекта JSON с использованием привязок Knockout foreach
. (Таблица большая, но не огромная: 20 столбцов и 200 строк или около того.)
Поскольку таблица большая, ее можно открыть/закрыть пользователем, нажав кнопки. Данные <table>
помещаются внутри элемента <div>
, который можно скрыть/показать с помощью методов jQuery .hide()
и .show()
(которые по существу работают путем установки и очистки CSS display: none
на <div>
).
Вся эта функциональность работает. Тем не менее, я замечаю, что после "закрытия" (скрытия) таблицы больших данных использование процессора Chrome скачкообразно - на 100%, если таблица с генерируемым нокаутом достаточно велика. Еще интереснее то, что это происходит только после того, как пользователь щелкнул где-то внутри элемента <div>
, который содержит таблицу, когда она отображается. Когда таблица скрыта (и загрузка процессора высока), щелчок в другом месте страницы вернет загрузку ЦП в нормальное русло. Процесс будет повторяться по желанию.
Еще одно полезное замечание: если я остановлю потоковые данные с сервера, эта проблема не произойдет (или это не заметно при использовании ЦП). На этой странице есть одна модель представления нокаута, которая управляет потоковыми данными с сервера и созданием этой таблицы данных из объекта JSON. Оба набора данных в остальном полностью разделены - ни одна из изменяющихся данных не отображается в таблице, и таблица не содержит привязки событий к модели представления. Как будто обновление потоковых данных модели Knockout вызывает работу над таблицей данных, даже если ни одна из данных потоковой передачи не привязана к таблице. И это происходит только тогда, когда таблица не отображается!
Краткое резюме:
- Веб-приложение использует нокаут для визуализации большой таблицы данных при загрузке страницы.
- Эта таблица скрыта при
.hide()
при запуске в $(document).ready
, но отображается с помощью .show()
после нажатия кнопки и может быть снова скрыта
- Если щелкнуть мышью внутри таблицы данных, использование ЦП в Chrome переместится на 100% после того, как таблица снова будет скрыта.
- Щелчок по чему-либо еще на странице приведет к нормальному использованию ЦП.
Другая важная информация:
- Профайлер Chrome JavaScript показывает высокую загрузку процессора, но он классифицируется просто как (программа).
- Ни IE10, ни Firefox 20 в Windows не показывают эту проблему.
Любые идеи о том, что происходит здесь, или предложения по дополнительным устранению неполадок?
jsFiddle:
Пример здесь: http://jsfiddle.net/CTYMv/6/
Посмотрите на использование ЦП после загрузки скрипта, он должен быть низким. Нажмите "Показать таблицу", а затем щелкните где-нибудь внутри всплывающего div (серый фон). Затем нажмите "Скрыть таблицу" - использование ЦП значительно возрастет. Затем щелкните в другом месте (белый фон), и CPU вернется в нормальное состояние.
Ответы
Ответ 1
Я думаю, теперь мы можем утверждать, что это ошибка в движке webkit. Эта ошибка появляется только при использовании свойства css display:none;
. Это связано с тем, как графический процессор с использованием webkit визуализирует скрытые элементы? Ну, я до сих пор не знаю...
СМОТРЕТЬ ДЕМО
Это простейшее обходное решение, о котором я могу думать, это не должно мешать никакому другому вашему коду: {например, нокаут наблюдаемый}
CSS:
{добавлены указатели-события, предложенные Брэндоном}
.hidden{opacity:0;pointer-events:none} //don't use display:none here
JS:
//don't use hide/show jq methods as internally it set display none (fadeOut() methods too)
$('#btn_show').click(function(){
$('#bigdatadiv').removeClass('hidden');
});
$('#btn_hide').on('click',function(){
$('#bigdatadiv').addClass('hidden')
});
Я знаю, что это всего лишь обходной путь и который все еще не отвечает на ваш вопрос: почему это происходит?
Ответ 2
Спасибо за эту тему; вы могли бы подумать, что ошибка будет исправлена через 2 года.
window.getSelection(). removeAllRanges() разрешил для меня вещи и был самым простым в моем коде.
Ответ 3
Просто используйте window.getSelection().removeAllRanges()
перед .hide();
для больших блоков. Работа для меня прекрасна.
Это глупо, но это правда.