Гарантируется ли, что событие загрузки для тега <script>всегда запускается сразу после выполнения скрипта? - PullRequest
0 голосов
/ 06 февраля 2019

Предположим, есть два файла JavaScript.

one.js

window.a=1;

two.js

window.a=2;

И загрузчик: loader.html

<body></body>
<script>
const s1=document.createElement("script");
s1.src="one.js";
s1.addEventListener("load",()=>console.log("one.js",window.a));
const s2=document.createElement("script");
s2.src="two.js";
s2.addEventListener("load",()=>console.log("two.js",window.a));
document.body.appendChild(s1);
document.body.appendChild(s2);
</script>

Всегда ли он воспроизводится как [Out-1] или [Out-2]?(Отредактировано: это означает, что «я не хочу код, который всегда производит [Out-1]», и «я хочу код, который всегда производит [Out-2]». Оба [Out-1] и [Out-2] являются приемлемыми.)

[Out-1] (Запуск в порядке s1-exec-> s1-onload -> s2-exec -> s2-onload. Все в порядке):

"one.js" 1
"two.js" 2

[Out-2] (s2-exec-> s2-onload -> s1-exec -> s1-onload. Это тоже нормально):

"two.js" 2
"one.js" 1

Меня беспокоит, является ли браузерможет работать в порядке s1-exec -> s2-exec -> s1-onload -> s2-onload и выдавать как [Out-3]

[Out-3] (не в порядке):

"one.js" 2
"two.js" 2

Я проверил спецификацию HTML5 https://www.w3.org/TR/2008/WD-html5-20080610/tabular.html#script

и там написано:

Если загрузка прошла успешно

  1. Если элемент скриптаДокумент является активным документом в контексте просмотра, пользовательский агент должен выполнить скрипт: ....
  2. Затем пользовательский агент должен запустить событие загрузки в элементе сценария.

Гарантирует ли это, что «другие теги сценариев никогда не прерывают процесс между этапами 1 и 2»?.

(отредактировано) Иными словами, мне интересно, требует ли спецификация HTML, чтобы браузер выполнял шаги с 1 по 2 синхронно (заголовок «немедленно» означает это).

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

событие load никогда не сработает немедленно, потому что:

Событие load вызывается, когда ресурс и его зависимые ресурсы закончили загрузку .

встроенная функция самовызвания - самая близкая к «немедленной»:

(function(){console.log("self-invoked");})();
0 голосов
/ 06 февраля 2019

По крайней мере согласно спецификациям (реализация никогда не гарантируется). Да, гарантируется, что событие загрузки запускает в конце «выполнения блока скрипта» , но... Я не уверен, что это гарантирует, что ваш обработчик событий будет вызван после.

Так что вы наверняка можете столкнуться с [out-1] и [out-2], но [out-3] менее понятен.

Когда вы добавляете элемент в документ, он будет загружен как скрипт async.Это означает, что порядок выполнения между script-1 и script-2 не может быть гарантирован.

// scr1 will load an external script
const scr1 = document.createElement('script');
scr1.onload = e => console.log('1', window.$);
scr1.src = 'https://cdn.jsdelivr.net/gh/jquery/jquery@3.2/dist/jquery.js?' + Math.random();
// scr2 will load a dataURL script
const scr2 = document.createElement('script');
scr2.onload = e => console.log('2', window.$);
scr2.src = 'data:application/javascript,$="script 2"';

// even though scr1 is appended first
document.head.appendChild(scr1);
document.head.appendChild(scr2);

Однако, хотя они и просят запустить событие в конце выполнения сценария блока algortithm, я должен признать, что не ясно, есливозможно, что когда-либо возникнет условие состязания и что два исполняют блок сценария до того, как будет обработан первый обработчик события загрузки (поскольку он может быть вызван только при следующем цикле событий).

Но я думаю, мы можем предположить, что все в порядке, так как шансы на это очень малы.
Кроме того, кажется, что по крайней мере Firefox и Chrome выполняют обратный вызов события в том же цикле событий, что ивызвало событие (между выполнением сценария и обратным вызовом при загрузке прошло менее 1 мс).

// both will load a dataURL where the execution time will get stored (minimal time possible)
// in onload events we will log
// both the script's execution time and the event's handler time
const scr1 = document.createElement('script');
scr1.onload = e =>
  console.log('1', window.$, performance.now());
scr1.src = 'data:application/javascript,$=performance.now()';

const scr2 = document.createElement('script');
scr2.onload = e =>
  console.log('2', window.$, performance.now());
scr2.src = 'data:application/javascript,$=performance.now()';

document.head.appendChild(scr1);
document.head.appendChild(scr2);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...