Выполнить запись в документе: невозможно выполнить запись в документ из асинхронно загруженного внешнего скрипта, если он явно не открыт.

#javascript #asynchronous #onload #document.write

#javascript #асинхронный #onload #document.write

Вопрос:

Я пытаюсь загрузить определенный скрипт после выполнения загрузки страницы, что-то вроде этого:

 function downloadJSAtOnload(){
            var element = document.createElement("script");
            element.src = "scriptSrc";
            document.body.appendChild(element);
        }

         if (window.addEventListener)
                  window.addEventListener("load", downloadJSAtOnload, false);
            else if (window.attachEvent)
                  window.attachEvent("onload", downloadJSAtOnload);
            else window.onload = downloadJSAtOnload;
  

И хотя этот скрипт, похоже, выполняет и загружает ‘ScriptSrc’ и добавляет его прямо перед концом тега body, он выдает следующее сообщение (не ошибку) в консоли (chrome)

Не удалось выполнить «запись» в «Документе»: невозможно выполнить запись в документ из асинхронно загруженного внешнего скрипта, если он явно не открыт.

Что это вообще значит? И должен ли я сделать что-то по-другому? Даже если я получаю ожидаемое поведение?

Комментарии:

1. Это означает, что загружаемый вами скрипт выполняется document.write , что не поддерживается при добавлении его на страницу через <script> тег. Вероятно, вам следует посмотреть, что делает скрипт, и изменить сценарий, чтобы он не использовался document.write .

2. понял, но я не могу изменить этот скрипт. Назовите это бюрократией. Могу ли я заставить скрипт загружаться синхронно? Нет права, потому что это происходит после загрузки страницы.

3. Да, вы можете загружать содержимое скрипта синхронно с AJAX, а затем eval с ним, хотя я не уверен на 100%, сработает ли это.

4. недавно нашел фантастическую библиотеку на github, которая прекрасно обходит это «ограничение»: github.com/krux/postscribe

5. @universio Я также сталкиваюсь с такой же проблемой. document.write('x3Cscript type="text/javascript" src="http://ads.appnexus.com/ttj?id=xyzpqramp;cb=${CACHEBUSTER}">x3C/script>'); это работает отлично, но когда я создаю скрипт с помощью createElement(‘script’) Я сталкиваюсь с той же проблемой. Можете ли вы предложить что-нибудь здесь?

Ответ №1:

Асинхронно загруженный скрипт, скорее всего, будет запущен ПОСЛЕ того, как документ будет полностью проанализирован и закрыт. Таким образом, вы не можете использовать document.write() из такого скрипта (ну, технически вы можете, но он не будет делать то, что вы хотите).

Вам нужно будет заменить любые document.write() операторы в этом скрипте явными манипуляциями с DOM, создав элементы DOM, а затем вставив их в конкретный родительский элемент с .appendChild() .insertBefore() помощью параметра или или .innerHTML или какого-либо механизма для прямого манипулирования DOM, подобного этому.

Например, вместо этого типа кода во встроенном скрипте:

 <div id="container">
<script>
document.write('<span style="color:red;">Hello</span>');
</script>
</div>
  

Вы могли бы использовать это для замены встроенного скрипта выше в динамически загружаемом скрипте:

 var container = document.getElementById("container");
var content = document.createElement("span");
content.style.color = "red";
content.innerHTML = "Hello";
container.appendChild(content);
  

Или, если в контейнере не было другого содержимого, к которому вам нужно было просто добавить, вы могли бы просто сделать это:

 var container = document.getElementById("container");
container.innerHTML = '<span style="color:red;">Hello</span>';
  

Комментарии:

1. Но разве я не делаю что-то подобное, когда указываю «document.body.appendChild(элемент)»?

2. @jfriend, повторите » но он не будет делать то, что вы хотите «, что, если это произойдет? Как мне включить его, если я этого хочу? (Раньше это работало в старых браузерах.)

3. @Pacerier — использование document.write() после завершения загрузки документа приводит к очистке текущего документа, а затем запись переходит в новый пустой документ. Если вы хотите такого поведения, просто очистите текущий DOM перед вставкой вашего содержимого. Если у вас есть более подробный вопрос, чем этот, пожалуйста, задайте новый вопрос, покажите код, который у вас есть, и опишите желаемый результат.

Ответ №2:

Немного поздно для вечеринки, но Krux создал для этого скрипт под названием Postscribe . Мы смогли использовать это, чтобы обойти эту проблему.

Комментарии:

1. каков наилучший способ передать эту библиотеку с помощью нашей библиотеки JavaScript? Ситуация такова, что мы даем теги JS клиенту, который запускается на этом веб-сайте.

2. Я не уверен на 100%, о чем вы спрашиваете здесь @RockStar, но любые обычные способы включения JS должны работать. Можно подтянуть cdnjs.com/libraries/postscribe и копировать/вставить код в существующий файл JS, или вы могли бы просто добавить <script> tag pointing to the cdnjs-hosted version of the file. Возможно, вам понадобится, чтобы он загружался перед другими скриптами, поэтому, если у вас возникли проблемы с его работой, это может быть возможной причиной.

3. Мы предоставили владельцу веб-сайта ссылку JavaScript CDN для размещения рекламы с использованием этого тега. Мы не можем попросить каждого владельца разместить это postscribe.js поэтому нам нужно предоставить его с помощью нашего JS.

4. postscribe, похоже, вообще ничего не делает, если вы явно не используете postscribe функцию — очень разочаровывает

5. @RockStar Какое решение вы получили для своей проблемы. Даже у меня такая же проблема

Ответ №3:

В случае, если это кому-то полезно, у меня была такая же проблема. Я вводил нижний колонтитул на веб-страницу с помощью jQuery. Внутри этого нижнего колонтитула были некоторые скрипты Google для рекламы и переназначения. Мне пришлось переместить эти скрипты из нижнего колонтитула и поместить их непосредственно на страницу, и это устранило уведомление.

Комментарии:

1. У меня была такая же проблема, но скрипт находился внутри пакета, созданного менеджером тегов. Проблема была вызвана async атрибутом, и единственным решением было удалить этот атрибут, поскольку мне не разрешено перемещать скрипты из нашего менеджера тегов.

Ответ №4:

Вы также можете вызвать

 document.open() before document.write()
  

вызовите

 document.close() 
  

когда вы закончите.

Возможно, это не лучшая практика для реальной веб-страницы, Но для тестирования и т. Д. Можно использовать.