Последнее обновление:
Почему зависает браузер
Статья рассчитана на специалистов в области веб-разработки, в частности, касается языка javascript
Вообще, причин, по которым может зависать браузер (целиком или одна из его вкладок) - немало. Если браузер условно старый, т.е. сделан лет 10 назад, то если зависнет одна из вкладок, зависнет и весь браузер. Это происходило по той причине, что в те времена браузеры, как правило, делались так, что функционирование их осуществлялось на основе одного процесса.
Потом разработчики браузеров стали выполнять многопроцессные браузеры. Например, Microsoft дошла до того, что каждой вкладке браузера Edge соответствует отдельный процесс. И все бы ничего, до тех пор, пока открытых в браузере вкладок - сравнительно немного, ну, не более сотни. А вот при большом количестве открытых вкладок в операционной системе появится и соответствующее число открытых процессов... что, как минимум, не есть хорошо, ибо расходует (практически впустую) ресурсы компьютера. Конечно, Microsoft об этом "позаботилась", и, схитрив, решила ограничить число вкладок.
Т.е. формально-то браузер Edge не имеет таких ограничений; просто по мере открытия очередной вкладки ширина каждой из ранее открытых вкладок сужается. И в итоге пользоваться браузером становится невозможно. Вроде бы, аналогичным нюансом страдает и Google Chrome. Ну, а в интернетах-форумах тролли убеждают друг друга в том, что, якобы, пользователю "не нужно" открывать в браузере сотни вкладок.
Т.е. многопроцессные браузеры, строго говоря, неудобная, малофункциональная вещь. НЕ предназначенная для активной и масштабной работы и вебсайтами. Правда, у них есть плюс: зависание одной из вкладок не влияет на другие вкладки и на работу браузера в целом.
Вкладка может зависнуть, например, если выполняется синхронный запрос AJAX и на него долго нет ответа. Правда, сейчас (2024 год) такие запросы уже (совершенно незаслуженно, ибо иногда без них обойтись сложно) считаются устаревшими, т.е. deprecated
.
Вкладка может зависнуть и, банально, при недостаточно быстром интернет-соединении. Или, если на соответствующей странице выполняется ресурсоемкий, длительный скрипт JS.
В конце концов, зависание может быть вызвано и попросту нехваткой оперативной памяти компьютера. Да есть и еще причины. Чтобы хотя бы кратко проанализировать их - потребуется немало времени.
Мы ниже рассмотрим одну из них, так скажем, нетипичную, но которая может иногда серьезно озадачить разработчика. Который в результате может потратить долгие дни и ночи на выяснение, "почему что-то идет не так".
Речь пойдет об изменении (динамически создаваемого) гипертекстового контента очень большого объема. Начиная от нескольких (десятков) мегабайт.
React
, Angular JS
и прочие Vue
. Именно тогда появилась мода на JS-приложения. На наш взгляд, совершенно излишняя мода, которая, вероятно, исчезнет. Когда разработчики реально захотят делать быстрые сайты.Впрочем, такой нюанс может возникнуть даже и на сравнительно легком, самописном сайте, не использующем указанные выше громоздкие технологии.
Итак, есть html-страница, имеющая гипертекстовый контент объемом от нескольких (десятков) МБ
Одно дело, когда такой контент является статическим. Т.е. как попал на страницу, отрендерился браузером, отобразился на экране тем или иным образом, так и всё. Это еще пол-беды, браузер вполне может освоить и 30 и более мегабайт контента.
И совсем другое, когда теги (блоки) с ним начинают изменяться в размерах, перемещаться (т.е. менять свои координаты). Вот тут браузер вполне может показать свой "норов". Например, взять, да и "подвесить" вкладку. А если это - старый браузер, то - и весь браузер. Вплоть до того, что придется выгружать такой браузер из оперативной памяти.
Самое печальное, что подобная ситуация даже в одном и том же браузере, для одной и той же вкладки появляется не всегда. Играет свою роль и иные, помимо браузера, программы, запущенные на компьютере, его ресурсы, особенности настроек и... еще неизвестно, что. Но, важно знать о такой, не очень приятной, возможности. Чтобы заранее как-то снизить ее влияние.
Перейдем к делу. Вот тестовый JS-код:
var div1 = document.createElement('div');
div1.style.cssText = 'max-width:30px; max-height:30px; border:solid; overflow: hidden';
document.body.appendChild(div1);
var div = document.createElement('div');
div.style.cssText = 'max-width: 70%; border: solid; display: block; max-height: 80vh; overflow: auto; word-break: break-all; position: relative';
var str = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAQ4CAIAAABnsVYUAAAgAElEQVR4nOS92Y4kS37eGa9C8RwO5h0GA0KixG7NvMHoZgiCQzXRlARdCNTwomcgkhcE2X1OVWZV5RL77u7h+74vEZlZdU431TMX8zbUxef2xT88sqobgyZAQgVHwdPDF3Nzc3Ozn332/Uezu58tHr5djd9iWT6+WT6+WY3fric33Lh4+BbL/';
var max = str.length;
for(var i = 0; i < 10000004; i++){
var pos = Math.floor(Math.random(max) * max);
str += str.slice(pos, pos+1);
}
div.textContent = '' + str + '';
div1.textContent = div.textContent;
alert('Создали элемент, содержащие большое внутреннее содержимое: '+ str.length + ' символов');
document.body.appendChild(div);
var butt = document.createElement('button');
butt.textContent = 'Сдвинуть вправо';
butt.style.cssText = 'display: inline-block; height: 30px; margin-top: 10px';
butt.onclick = function () {
//alert('Пытаемся сдвинуть элемент с большим количеством содержимого...');
var offs = div.offsetLeft;
div.style.display = 'none';
div.style.left = offs + 10 +'px';
div.style.display = 'block';
};
document.body.appendChild(butt);
Этот код создает на странице два блока div
. В каждый из них он записывает более 10 МБ текстового содержимого - псевдослучайных символов. Имитируя код рисунка (картинки) по протоколу data
.
Наконец, код создает кнопку, по нажатию на которую происходит перемещение одного из блоков на 10px
вправо.
Отметим сразу, что на практике оказалось НЕВОЗМОЖНЫМ достоверно реализовать зависание вкладки того или иного браузера, выполняющего такой код. Иногда вкладка зависает надолго; а иногда - лишь на несколько секунд. Иногда же - практически вообще не зависает, особенно, после повторных нажатий кнопки.
Однако, нет никакой возможности привести тот код, по причине его достаточно большого объема (более 9 тыс. строк только в одном модуле). Поэтому был создан приведенный выше простой тестовый пример, который, к сожалению, не моделирует проблему на 100%, но, по крайней мере, дает некое представление. И, самое главное, способ решения проблемы, который позволил избежать такого зависания, обсуждается ниже на данном примере.
Код - кроссбраузерный и должен работать чуть ли не в Internet Explorer.
Результаты
И вот что получилось при тестировании такого кода.
Операционная система Windows 7
Браузер IE11. Вкладка зависла надолго и не реагировала ни ни какие действия.
Браузер Firefox 24. При обновлении вкладки через несколько секунд появляется сообщение "Создали элемент, содержащие большое внутреннее содержимое:... "
.
Затем появляются два блока и кнопка. После ее нажатия вкладка (вместе со всем браузером) зависает на примерно 16 секунд, а то и дольше.
После этого нижний блок сдвигается вправо на 10px
. А вот после очередных нажатий кнопки она перемещается вправо уже через 4 секунды (или даже меньше), т.е. гораздо быстрее.
Браузер Firefox 36. После обновления страницы и появления указанного сообщения точно так же появляются блоки и кнопка. Иногда (но не всегда) после первого нажатия на кнопку вкладка (вместе с браузером) зависает на 16 секунд; но, чаще всего - на 4 секунды. А при последующих нажатиях перемещение блока происходит гораздо быстрее, менее, чем за 1 секунду.
Хостовая операционная система Windows 7. В ней установлена виртуальная машина Virtual Box, а в ней - Windows 7
Браузер Firefox 45. Результаты примерно аналогичны браузеру Firefox 36, только, такое впечатление, перемещение блока происходит еще слегка быстрее.
Браузер Edge 109 (64 бит). Вкладка не запустилась вообще, как и в IE11. Браузер периодически выдавал сообщения, что, мол, вкладка зависла и нужно ли ожидать или нужно закрыть ее.
Браузер IE9. Вкладка зависла надолго и не реагировала ни ни какие действия.
И, теперь главное
Обратите внимание на строчку в тестовом примере, выделенную жирным шрифтом:
div.style.display = 'none';
Был придуман такой "хак". Перед тем, как сдвигать блок с большим количеством контента, делаем этот блок незаметным, т.е. устанавливаем для него display:none
. И после передвижения - восстанавливаем видимость при помощи
div.style.display = 'block';
Так вот, если закомментировать строчку, выделенную жирным шрифтом (т.е. не делать перемещаемый блок незаметным), то в Firefox 24 время ожидания после первого нажатия кнопки, в среднем, увеличивается. Хотя, такое увеличение наблюдается далеко не всегда. Что, собственно, и сбивает с толку.
А в Firefox 36, 45 такого влияния, вроде бы, нет. Браузеру Edge - совершенно без разницы, он упорно не желает работать с этим JS-кодом.
Так что указанный "хак" вы, как разработчик, можете взять себе на заметку. Если ваш JS-код выполняет некое перемещение или изменение размеров блока, содержащего очень большой объем контента, лучше, на всякий случай, предварительно сделать его невидимым, а потом, после выполнения операции, вновь показать на экране. Так вы можете застраховаться от зависания вашего кода в некоторых браузерах.
О причинах тут можно лишь гадать. Возможно, причиной является не совсем оптимальная работа браузера Firefox 24 с видео-драйвером операционной системы. Вероятно, в более свежих версиях Firefox такая работа была оптимизирована.
Ну, а Edge... что с него взять-то. Он даже загрузить страницу с указанным выше JS-кодом не может. Будет интересно, каковы результаты тестирования данного в других браузерах.