В спецификации WHATWG есть интересный этап подготовки элемента сценария:
В противном случае немедленно выполните элемент сценария el, даже если другие сценарии уже выполняются.
Что это за случай? Как один скрипт может приостановить выполнение другого скрипта?
@Barmar Я понимаю это, но я хочу знать, что об этом говорит спецификация; каков реальный код этого примера?
Я думаю, что единственный случай, когда это происходит во время выполнения другого скрипта, — это когда скрипт делает что-то вроде script document.createElement("script"); script.src = "URL"; document.body.appendChild(script);. Интерпретатор просто блокируется до тех пор, пока сценарий не будет получен, выполняет содержащийся в нем код, а затем возобновляет работу с того места, где он остановился.
@Barmar Нет, элементы сценария, вставленные в DOM, не блокируются.
@Bergi Конечно, ты прав. Вот почему вам нужно использовать прослушиватель событий load для кода, который зависит от этого скрипта.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Учитывая ограничения, это скрипт, который не является модулем, не имеет атрибута src и вставляется во время выполнения скрипта. Я думаю, что следующий пример подходит:
<script>
console.info("before");
document.write(`<script>
console.info("nested");
</script>`);
console.info("after");
</script>хм, я пытался привести тот же пример, но </script>. Почему это так важно?
Вы имеете в виду опустить это?
Я имею в виду </script> вместо </script> в document.write
@MaximPro Символ «\» используется для экранирования специальных символов и обозначает, что следующий символ «/» следует понимать буквально, независимо от контекста, он может означать что-то другое. Иногда это считается хорошей практикой, хотя здесь, насколько я вижу, в этом нет необходимости, поскольку «/» в этом контексте не имеет особого значения.
@DanielCruz Попробуйте без... :)
@DanielCruz это имеет значение, протестируй без обратной косой черты
@MaximPro, Кей, я понимаю, значит, это зависит от контекста выполнения? Я тестировал консоль разработчика браузера, и она отлично работает как с ней, так и без нее. Извините, если я неправильно информировал :(
@DanielCruz Да, я думаю, что здесь парсер HTML и парсер JS борются друг с другом, в чистом JS все в порядке.
@DanielCruz, если честно, я не знаю, почему в document.write нужно писать обратную косую черту, правила парсера об этом ничего не говорят, по крайней мере, я не видел.
@MaximPro Парсер HTML здесь довольно тупой, у вас есть открывающий тег <script>, он соответствует </script> , он ничего не знает о Javascript, поэтому ничего не знает о литералах шаблона или строковых литералах, он просто ищет </script>.. Экранирующий Берги поставил предотвращает совпадение первого тега <script> с внутри части Javascript.
@Кейт, как парсер интерпретирует </script>? это не соответствует </script>
Аааа @Кейт, я понимаю, поэтому экранирование сделано для того, чтобы парсер HTML понимал, что тег сценария не закрывается внутри строкового литерала. Как только js сможет проанализировать содержимое, для него это то же самое «/», что и «/», но необходимо выполнить экранирование, чтобы предотвратить преждевременное закрытие тега сценария во время анализа HTML?
@MaximPro Да, как сказал Кит, </script> используется для того, чтобы парсер html не интерпретировал его как закрывающий тег внешнего скрипта. Затем интерпретатор JavaScript создаст из этого кода обычное строковое значение </script>, которое запишется в документ. Есть много способов снять шкуру с этого кота , например с помощью '<'+'/script>', ответный подход самый короткий (и самый коварный). Довольно стандартный шаблон из былых времен, когда загрузка скриптов через document.write была обычным явлением :-)
@Bergi Keith, спасибо, я бы удалил свой комментарий, но тогда ваши комментарии будут вырваны из контекста, поэтому я просто отредактирую, чтобы указать, чтобы прочитать комментарии ниже. * Редактировать: я не могу редактировать свой комментарий :'( кажется, редактировать можно только в течение определенного периода после комментария.
@Bergi, точно, когда анализатор просматривает входной поток, он обнаруживает, что его закрывающий тег находится в document.write, но document.write еще не выполнен. Таким образом, остальная часть сценария оказывается вырванной из контекста.
@Bergi исправьте свой ответ, вы написали «не вставлено в парсер», но оно «вставлено в парсер», иначе скрипты будут выполняться последовательно
@MaximPro На самом деле я думал избежать условия, описанного в пункте 34.2., но на самом деле я не знаю, как создать таблицу стилей, блокирующую сценарии. Кроме того, когда когда-либо вызывается подготовка элемента сценария для элемента, не вставленного в анализатор?
@Bergi, это просто, просто вставьте внешнюю таблицу стилей перед тегом сценария (таблица стилей должна следовать за ). Случай без синтаксического анализа — это когда вы вставляете скрипт с помощью метода добавления ( случаи без синтаксического анализа описаны здесь).
@Bergi, кстати, я нашел ошибку в Chrome, уровень вложенности скриптов для вложенных скриптов всегда будет больше 1, поэтому это должно быть в случае прерывания родительского скрипта, но если вы вставите внешнюю таблицу стилей перед скриптом в document.write, вы получите выполнение скриптов последовательно, пример, Firefox в этом случае работает корректно в отличие от Chrome
@MaximPro Могу поклясться, что я попробовал это - мне не пришло в голову, что это может быть ошибка браузера! Что касается скриптов, не вставленных в парсер (встроенных), я думал, что они вообще не будут выполняться, но, видимо, я перепутал добавление DOM с .innerHTML и .insertAdjacentHTML, поэтому мой эксперимент провалился.
@Bergi, когда парсер HTML встречает токен <script>, он устанавливает для флага элемента сценария значение, которое уже началось, равным true , что не позволяет подготовить элемент сценария, даже когда сценарий узла будет вставлен в DOM после анализа фрагмента процесс, поэтому innerHTML не вызывает скрипт (на всякий случай добавил этот комментарий).
Это как если бы содержимое второго скрипта было внутри первого скрипта.