или как использовать document.write без проблем с document.write

По мере того, как мы переходим на новую инфраструктуру показа рекламы и переделываем наш код доставки, появилось требование показывать только неблокирующую рекламу. Таким образом, нам пришлось избавиться от устаревшей реализации document.write, которая до сих пор слишком широко распространена в рекламе.

Этот пост предназначен для того, чтобы помочь другим в поиске возможного решения для обеспечения асинхронного обслуживания кода своих клиентов/клиентов и, таким образом, сокращения времени загрузки страницы.

47% потребителей ожидают, что веб-страница загрузится за 2 секунды или меньше.

https://blog.kissmetrics.com/loading-time/

Уже есть несколько сообщений в блогах, освещающих проблемы document.write, но очень немногие предлагают решения. Дальнейшее чтение по вопросу:



В процессе мы нашли несколько решений:

Используйте innerHTML для добавления рекламного кода

Это работает только для комбинаций текста/изображения, без тегов ‹iframe› и ‹script›.

Создайте все элементы вручную, прежде чем добавлять их

Это было бы предпочтительным решением, однако оно оказалось непрактичным из-за различий в рекламных кодах и реализациях рекламных серверов наших клиентов.

Анонимные фреймы

Это оказалось лучшим решением нашей проблемы, оно может заменить document.write и адаптироваться к нашим требованиям без больших накладных расходов и с достаточной обратной совместимостью для всех основных версий браузеров.

Да, мы будем использовать document.write, хотя мы будем использовать его неблокирующим образом в анонимном Iframe. Вот фрагмент кода:

var d = document;
var i = d.createElement("iframe");
var ad = 'some weird html code with a<script>alert("that is executed");</sc'+'ript>'
var frameHTML = '<!doctype html><html><head><title></title></head><body style="margin:0;padding:0">' + ad + '</body></html>';
if (navigator.userAgent.indexOf("MSIE") == -1 && navigator.userAgent.indexOf("Opera") == -1) {
    i.contentDocument.write(frameHTML);
    i.contentDocument.close();
} else {
    if (document.domain != location.hostname) {
        i.src = "javascript:var d=document.open();d.domain='" + document.domain + "';void(0);";
    }
    i.contentWindow.contents = frameHTML;
    i.src = 'javascript:window["contents"]';
}

Последующая проблема — где разместить Iframe?

Раньше document.write помещал ваш рекламный код сразу после исходного тега ‹script›, но теперь вам нужно найти место, куда вставить анонимный Iframe самостоятельно. Вы также должны убедиться, что вы вставляете его после правильного тега сценария, также возможно, что один и тот же тег сценария вставляется несколько раз на текущую страницу.

Для всего, кроме IE, это действительно просто, вставьте его после document.currentScript, но для IE?

  1. Вы можете вставить его после текущего скрипта, если у него есть идентификатор.
  2. Вы можете вставить его после текущего скрипта, если вы идентифицируете его с помощью атрибута src.
  3. Вы можете вставить его, используя оба приведенных выше решения, и объединить его с атрибутом данных, который сообщает, был ли уже вставлен Iframe после элемента, который даст вам:
var d = document,
    // ID of the TAG (also used in the src)
    t = 'OLy5bo3cdA7fjuOilPMl',
    // get our ad tag as dom element
    // currentScript works for every browser but IE
    // in IE we try to get our tag by id
    p = d.currentScript || d.getElementById(t);
// FALLBACK for IE, if no id was set on the tag or tag is "used"
if (!p || p.hasAttribute("data-placed")) {
    var ds = d.getElementsByTagName("script");
    for (var i = ds.length; i > 0; --i) {
        var s = ds[i];
        if (s 
         && s.src 
         && s.src.match(t) 
         && !s.hasAttribute("data-placed")
        ) {
            p = s;
            break;
        }
    };
}
// Mark Tag as "used"
p.setAttribute("data-placed", t);
// Insert Iframe after tag
p.parentNode.insertBefore(i, p.nextSibling);

Вы можете просмотреть весь код здесь и увидеть его в действии здесь.

Спасибо Рене Баудишу @ Media Impact