Возникли проблемы с сортировкой правильного подхода к обработке события загрузки в Chrome при загрузке объектов HTML.
Я использую объекты HTML для загрузки виджетов в веб-панель управления, и событие загрузки выглядит нарушенным в Chrome, поскольку я получаю повторное срабатывание события загрузки, но только если я установил стиль объекта в событии загрузки на позицию : absolute. К сожалению, для моего приложения это критическая функция, так как мне нужно разместить виджет в определенных местах экрана с помощью javascript.
Скрипка ниже помещает Chrome в бесконечный цикл, в то время как в других браузерах он запускается только один раз (хотя в моем приложении Chrome запускает событие загрузки дважды, а затем останавливается).
HTML
<div id = "container"></div>
<br/><br/><br/><br/>
<div id = "xx">Not Fired..."</div>
JavaScript:
var cnt = 0;
(function loadWidget() {
var widgetObj = document.createElement("object");
widgetObj.data = ("http://13.75.145.9/widgets/dial.html") // location of widget
var tt = document.getElementById("container");
tt.appendChild(widgetObj);
widgetObj.addEventListener("load", widgetLoaded, false);
})();
function widgetLoaded(e) {
cnt = cnt + 1;
document.getElementById("xx").innerText = "fired x" + cnt;
//any manipulation of style is OK, its only the position: absolute that causes re-firing
e.currentTarget.style = "cursor: move; text-decoration: overline";
e.currentTarget.style.setProperty("position", "relative");
// Uncomment out the line below in Chrome and the event will continuously fire, but only once in othe browsers
e.currentTarget.style = "position: absolute; left: 50px";
}
Я предполагаю, что это ошибка Chrome, и хотя я могу обойти ее, проверив, сколько раз объект был загружен, и досрочно завершил событие загрузки, это снижает производительность, потому что похоже, что весь объект перезагружается каждый раз (глобальный JavaScript в объекте запускается повторно) и при загрузке пары виджетов в качестве объектов браузер значительно замедляется, что влияет на работу конечного пользователя.
Независимо от того, что я пытаюсь, я не могу избежать повторных загрузок. Кто-нибудь еще видел этот баг и знает как избежать повторной загрузки?
В соответствующем примечании Chrome отобразит и отобразит объект, а затем переместит его в правильное положение, при котором экран мерцает, в то время как другие браузеры отобразят виджет в его конечном месте (после того, как загрузочный javascript был запущен), что является более приятным опытом и Я не могу найти способ дважды остановить рендеринг Chrome.
[Обновление от декабря '18] - обходной путь, описанный в ответах ниже, больше не работает с последней версией Chrome (71.0.3578.80), а Chrome дважды загружает объекты HTML и дважды запускает загруженные события. См. Это сообщение об ошибке Chromium для получения дополнительной информации: Ошибка Chrome с объектами HTML



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Не уверен в причинах такого поведения в Chrome. Однако обходным путем, похоже, является изменение стиля контейнера вместо стиля объекта - увидеть скрипку
function widgetLoaded(e) {
const target = e.currentTarget;
target.parentElement.style = "position: absolute; left: 50px;";
}
Также после некоторого расследования я обнаружил, что проблема, вероятно, вызвана изменением display с inline на block - увидеть скрипку.
@deandob, это может быть ошибка кроссбраузерного материала, который работает иначе. Но есть гораздо более простой обходной путь, см. Ответ, который я опубликовал.
Я все еще не могу решить последнюю часть этой проблемы - где хром будет отображать объект дважды (даже если событие загрузки запускается только один раз). В первый раз хром отображает объект в позиции 0,0, а затем, если он перемещает его в правильное место (слева: 50 пикселей), и вы видите, что объект мерцает на экране. Это очевидно на скрипке и делает работу с хромом в моем приложении визуально беспорядочной. Другие браузеры будут правильно отображать объект после завершения события загрузки. Я пробовал несколько вещей (например, убрать контейнер с экрана), но, похоже, ничего не изменило это поведение. Любые идеи?
@deandob в качестве опции вы можете использовать некоторые хитрости CSS - сделать ваш объект «невидимым» и показывать только после load - jsfiddle.net/xLzo25jp/8
@mykhailo, у меня есть до 50 объектов для загрузки на экран, поэтому переходы CSS, скорее всего, замедлят загрузку страницы (важна быстрая загрузка). Но если я установил ширину: 0 до загрузки объекта, а затем отрегулирую ширину после загрузки, Chrome теперь отображает изящно. Edge по-прежнему является проблемой, но я попробую несколько похожих советов, чтобы заставить его работать изящно (эти небольшие различия в поведении браузера раздражают ...)
@deandob transition в моем примере полностью необязателен, не стесняйтесь его пропустить. Рад слышать, что вы преодолели свои проблемы. И я полностью согласен, что эта проблема с load болезненна. Вы можете попробовать отправить эту проблему в трекер проблем с хромом
Получил, что это хорошо работает как для Edge, так и для Chrome, используя непрозрачность 0 в родительском div перед загрузкой виджетов, затем непрозрачность 1 после завершения всех событий загрузки. Красиво выглядит и хорошо работает - спасибо за советы.
Эта проблема вернулась с последней версией Chrome, ранее обходной путь для изменения отображаемого объекта: блок избегал двойного события для загрузки объекта, теперь он не работает в Chrome 71.0.3578.80 (ошибка двойного вызова события вернулась) . Посмотрите на эту скрипку, которая помещает последний цикл вызовов объектов Chrome, но запускается только один раз с другими браузерами. jsfiddle.net/xLzo25jp/5
Если у кого-то есть идея, как это обойти, напишите здесь. Подам в гугл как ошибку.
Обходной путь, приемлемый для моего приложения для предотвращения двойной загрузки, заключается в замене тега объекта тегом iframe - они очень похожи, работают одинаково (замените .data на .scr), и, согласно нашему тестированию, не имеют других побочных эффектов. .
Изменение блока отображения устраняет проблему для моего приложения. Другой вариант изменения стиля контейнера также возможен путем инкапсуляции объекта в DIV, однако для моего приложения блок отображения более подходит, спасибо.