Принудительный рендеринг, отрисовка, redraw, reflow ; во время работы с COM(ActiveX)
Всем доброго времени суток...
Проблема истрепала кучу нервов и времени, потому хочу поделиться соображениями, частичным решением, найденным материалом, дабы столкнувшиеся не корячились как я. Все началось с того, что клиентской части внутреннего сайта понадобилась работа с Excel на конечном компе юзверя, подумав, почитав, решили в пользу IE + ActiveX, а для филиалов не имеющих доступ к внутреннему сайту передать сие творение в виде *.hta (HTML Application) (типо убиваем двух зайцев :victory: ) (тем более прецедент уже есть - система "Контур Экстерн" которая только в IE и работатет) Ну вот и понеслась... логику отработали быстро, опыт COM-взаимодействия с Excel благо богатый, с JavaScript тоже проблем не имеем. Вот казалось бы и все, логика выполняется верно на связках: WinXP+IE8, Win7+IE8, Win7+IE9 (как в виде страницы сайта с разрешения юзверя, так и в виде *.hta приложения) Расчеты, чтение/заполнение таблиц, работа с файловой системой занимают от 5-6 до 15-20 сек, так что было решено анимировать процесс, дабы было видно что идет обработка. И тут началось... Пошли по классическому пути через setTimeout, setInterval, после нескольких неудач решили особо не мудрить - разбили логику на несколько последовательных функций, между которыми и будет происходить некая анимация - изменяться текст в <textarea id='satus'>Здесь будет статус выполнения</textarea> модель такая: myAnimation('выполняется myFunction1') myFunction1() myAnimation('выполняется myFunction2') myFunction2() myAnimation('выполняется myFunction3') myFunction3() myAnimation('выполняется myFunction4') myFunction4() myAnimation('выполняется myFunction5') myFunction5() myAnimation('выполняется myFunction6') myFunction6() myAnimation('Готово') function myAnimation(text){ var element = document.getElementById("status"); element.value = text }; и что вы думаете ? все myFunction*() успешно выполняются одна за одной... а вот в 'satus' отрисовывается только 'выполняется myFunction1'... и висит, потом когда все расчеты закончатся быстро мелькает 'выполняется myFunction6' и 'Готово' Часы "гугления", с десяток постов на разных форумах, все без толку. Вроде все должно работать... а не не работает. Так вот ИСТИНА !!! : Это особенность "осла", как только осел начинает работать с COM-компонентами, он в целях повышения производительности вырубает весь автоматический рендеринг(обоход DOM мол слишком дорогое удовольствие во время работы с COM), и пока объект "захвачен" без пинка ничего отрисовывать не станет... как же дать ему "пинка"! вот здесь, представлен такой список свойств елемента, обращение к которым вызовет принудительный reflow&redraw: Цитата:
В IE8, IE9 (в виде html, на XP или Win7, и только на Win7 в виде *.hta) - нам помогут свойства и 1-го пункта т.е. изменив функцию таким образом: function myAnimation(text){ var element = document.getElementById("status"); element.value = text element.offsetHeight }; мы добьёмся анимации... для *.hta в WinXP даже такой трюк не срабатывает хотя здесь представлено несколько иных способов, в том числе и среди коментов предлагают Цитата:
|
Цитата:
|
Если я не ошибаюсь, в качестве движка для HTA-приложений используется в XP IE6 в Win7 IE7, независимо от того какой браузер установлен в системе.
Для визуализации попробуйте использовать GIF-анимацию, вначале выводите гифку, загружаете все что нужно, удаляете гифку. |
Цитата:
1)Экземпляр COM-обекта в буквальном смысле захвачен процессом iexplore.exe в индивидуальном режиме (т.е. его handle принадлежит этому процессу, некую аналогию можно провести с ситуацией когда пытаетесь открыть файл который юзается какой-то софтой - если у файла есть открытый хендл, система сначала проверяет кому/какому процессу он принадлежит, потом в каком режиме он открыт, если режим индивидуальный то шлет вас "на...")... так вот пока у IE в стеке есть хоть один хендл экземпляра COM-объекта он всецело занят им - и рендерить сам собой ничего не будет. Это вот как раз случай с Excel... function Excelconnection(){ Excel = new ActiveXObject("Excel.Application"); Excel.Application.DisplayAlerts = false; Excel.Visible = false; }; так вот пока вы не открыли док - это просто ссылка на интерфейс а как только вы ActiveBook = Excel.Workbooks.Open('D:\\something.xls') это уже захваченный экземпляр COM-объекта, и исключительные права на него имеют теперь лишь он сам - процесс Excel.exe и его захватчик iexplore.exe, и просто закрыв док: ActiveBook.Close(true) вы не убьете захваченный экземпляр COM, вам надо убить сам процесс, т.е. закрыть апп: Excel.Application.Quit() вот теперь переменная Excel - снова просто ссылка на интерфейс "Excel.Application" 2)Инициализирован поток интерфейса OLE/COM... это интересный момент, это вот например: sysShell = new ActiveXObject("Shell.Application"); здесь мы не создаем экземпляров, это потоковый интерфейс, он запущен всегда (он являются частью ОС)... и вот здесь как только мы его объявили в стеке повис поток для общения с этим интерфейсом, и пока он открыт, IE считает его как бы аналогично захваченному экземпляру(я не так силен в системном программировании чтобы описать глубже этот процесс), но в данном случае убить его можно вот так: sysShell = null убили ссылку на поток, поток автоматически перестал существовать. Цитата:
|
Цитата:
|
вынести анимацию в iframe тоже не помогло...
|
Часовой пояс GMT +3, время: 04:10. |