Предотвращая сценарии прерывания операцииИсточник: thevista
Эта статья предоставляет некоторую дополнительную информацию и помощь владельцам веб-сайтов или сторонним библиотекам скриптов.
Напоминание В начале разработки IE8 мы занялись смягчением побочных явлений этой проблемы. Вместо того, чтобы выводить диалоговое окно и покидать страницу сразу после того, как вы нажимаете ОК, мы удалили диалоговое окно и перенесли уведомление об ошибке в строку состояния (область уведомления о скриптовых ошибках). В итоге вашу работу не прерывают диалоговым окном, и вы можете продолжить просматривать текущую веб-страницу. Вы можете даже не заметить, что эта ошибка произошла; однако работа анализатора HTML резко останавливается (только для этой вкладки) и никакой дополнительный контент никогда не будет обработан. Вскоре после выпуска IE8 мы начали получать сообщения от пользователей IE8, продолжавших видеть старое диалоговое окно о прерывании операции! Хотя мы знали, что не исправили все возможные сценарии, которые могут вызывать это диалоговое окно (оно может срабатывать из-за разных подсистем, таких как навигационный стек или сеть), мы были уверены, что учли худшие случаи. После получения недавних сообщений о том, что пользователи продолжают сталкиваться с окном "Операция прервана" в IE8, мы провели дальнейшие исследования для обнаружения дополнительных сценариев, которые могут вызывать появление этого диалогового окна (помимо скриптовой ошибки). В последующих двух сценариях основная причина проблемы прерывания операции все та же (для подробностей, пожалуйста, прочтите мою предыдущую статью), но то, как она происходит, в этих сценариях вынуждает IE обойти те изменения, которые мы внесли в IE8. Сценарий 1: Вложенный анализ после прерывания операции
Код:
<html>
<body> <div> <script type="text/javascript"> document.body.appendChild(document.createElement('div')); document.write("Testing"); </script> </div> </body> </html> В приведенном выше коде HTML первая строка скрипта призвана вызвать проблему с прерыванием операции. В IE8, как мы уже упоминали ранее, это учтено. Однако если где-то дальше происходит вызов API document.write, как показано во второй строке скрипта, все версии Internet Explorer, включая 8, выведут старое диалоговое окно о прерывании операции. Сценарий 2: Операция прервана в обработчике ошибок
Код:
<html>
<body> <script type="text/javascript"> window.onerror = function() { var el = document.getElementById("div2"); el.appendChild(document.createElement("div")); } </script> <div id="div1"></div> <div id="div2" onclick="alert('hi';"></div> </body> </html> В этом HTML-файле в скрипте (в обработчике события onclick) присутствует ошибка выполнения, которая приводит к вызову обработчика объектов onerror. В этом случае, если операция прерывается в обработчике ошибок, это диалоговое окно также будет показано в IE8. Программное определение прерывания операции Этот скрипт должен выполняться первым на странице, испытывающей проблему прерывания операции. Он не учитывает использование innerHTML и appendChild, проверяя границы разбора прежде, чем позволить действие. AppendChild, безусловно, самая широко используемая точка входа DOM, которая может вызвать прерывание операции, следующее за innerHTML. Этот скрипт может отметить ошибочные результаты, но мы хотели лишний раз перестраховаться. Этот скрипт основан на функции, включенной только в стандартном режиме IE 8 - Mutable DOM Prototypes. Таким образом, он будет работать только для страниц, использующих наиболее соответствующий стандартам режим IE. Ознакомьтесь с этой статьей о режиме совместимости, чтобы узнать подробности о режиме, в котором IE отображает вашу страницу. Однако те проблемы прерывания операции, которые обнаруживает этот скрипт (в стандартном режиме IE8), также относятся к IE7 и IE6, помогая, таким образом, исправить эту проблему в любой версии IE. Чтобы воспользоваться этим скриптом, следуйте нижеприведенным инструкциям:
2. Поместите следующий текст скрипта в скриптовый элемент (или соответствующий файл, обращение к которому происходит с помощью атрибута src) 3. Установите значения "f1" и "f2"
b. Установка истины для значения "f2" останавливает процесс выполнения в момент потенциальной ошибки прерывания операции и запускает отладчик (внешний или встроенный отладчик JavaScript). Здесь вы можете проанализировать каждое событие и увидеть, какие допущения были сделаны и как процесс выполнения может быть изменен для предотвращения проблемы. 4. В IE пройдите на данную страницу. 5. Запустите отладчик JavaScript нажатием "F12", затем выберите вкладку "Script" в Developer Tools и нажмите кнопку "Start Debugging".
Код:
(function() {
// Feature switches // WARNING: 'true' may cause alternate program flow. var f1 = PREVENT_POTENTIAL_OCCURANCES = false; var f2 = BREAK_INTO_DEBUGGER_AT_POTENTIAL_OCCURANCES = true; if (!window.console) { window.console = {}; window.console.warn = function() { }; } var frontierCheck = function(host) { // Is host on the frontier? while (host && (host != document.documentElement)) { if (host.parentNode && (host.parentNode.lastChild != host)) // This is not on the frontier return true; host = host.parentNode; } if (!host // (host != document.documentElement)) return true; // This node is not on the primary tree // This check is overly cautious, as appends to // the parent of the running script element are // OK, but the asynchronous case means that the // append could be happening anywhere and intrinsice // knowledge of the hosting application is required console.warn("Potential case of operation aborted"); if (f2) debugger; // Step up two levels in the call stack // to see the problem source!! if (f1) return false; else return true; } var nativeAC = Element.prototype.appendChild; Element.prototype.appendChild = function() { // call looks like this: // object.appendChild(object) // Go back one more level in the call stack!! if (frontierCheck(this)) return nativeAC.apply(this, arguments); } var nativeIH = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML").set; Object.defineProperty(Element.prototype, "innerHTML", { set: function() { if (frontierCheck(this)) nativeIH.apply(this, arguments); } }); })(); Мы понимаем, что диалоговое окно прерывания операции и его измененный вариант из IE8 остаются источником значительных неудобств для веб-разработчиков. Мы надеемся, что эта информация и приведенный скрипт помогут вам в диагностике и исправлении проблем, связанных с прерыванием операции в IE8 (и старших версиях IE). |