Запобігаючи сценарії переривання операції

Ця стаття надає деяку додаткову інформацію та допомогу власникам веб-сайтів або стороннім бібліотекам скриптів.



Нагадування
Приблизно півтора роки тому я написав статтю про помилку, яка може відбутися на деяких веб-сайтах, що генерує контент за допомогою скрипта. Цей контент може призвести HTML-аналізатор Internet Explorer в невідновні стан, що вдвічі ускладнює пошук і діагностику причин цієї помилки. Коли аналізатор HTML приходить у такий стан, він не може продовжити роботу і просто опускає руки, визнаючи: "Операція перервана!"

На початку розробки 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.

Щоб скористатися цим скриптом, нижченаведених інструкцій:




Код:
(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).

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*