Подтвердить что ты не робот

Часть JavaScript выполнена или не выполнена, если предыдущий script не работает

Я только что узнал важный факт о выполнении javascript в случае возникновения ошибки. Прежде чем я начну делать выводы из этого, я лучше проверю, прав ли я.

Учитывая HTML-страницу, включая 2 скрипта:

<script src="script1.js" />
<script src="script2.js" />

script1:

doSomething();

Скрипт2:

doSomeOtherThing();

Это приводит к тому, что один script обрабатывается как единое целое:

doSomething();
doSomeOtherThing();

В частности, если doSomething выдает ошибку, выполнение прерывается. "script2" никогда не выполняется.

Это мой "Урок 1" - можно подумать, так как это отдельный файл, на который он не влияет. Но это так. = > см. "последнее обновление" ниже


Теперь, если мы изменим script2 следующим образом (предположим, что мы включили jQuery где-то выше):

$(document).ready({ doSomeOtherThing(); });

и поместите script перед скриптом2:

<script src="script2.js" />
<script src="script1.js" />

Порядок выполнения по-прежнему остается "doSomething()" (иногда) "doSomeOtherThing()".

Однако он выполняется в двух "единицах":

  • doSomething выполняется в начале документа java script
  • doSomeOtherThing выполняется при обработке события document.ready.

Если doSomeOtherThing выдает исключение, он будет не разорвать вторую часть обработки.

(Я воздержусь от использования термина thread, потому что считаю, что все script обычно выполняются одним и тем же потоком, или, точнее, это может зависеть от браузера.)

Итак, моя Lession 2: хотя ошибка JavaScript может помешать выполнению любых последующих скриптов, она не останавливает цикл событий.


Заключение 1

$(document).ready() отлично справляется с определением фрагментов кода JavaScript, которые должны выполняться независимо от любых других исполняемых скриптов.

Или, другими словами: если у вас есть фрагмент JavaScript и вы хотите убедиться, что он выполняется, даже если другие скрипты не работают, поместите его в $(document).ready().

Это было бы ново для меня, потому что я использовал бы только событие, если script зависит от полностью загруженного документа.


Заключение 2

Сделав еще один шаг, было бы хорошим решением архитектуры обернуть все сценарии в $(document).ready(), чтобы убедиться, что все сценарии "поставлены в очередь" для выполнения. Во втором примере выше, если script2.js был включен после script1.js, как в примере 1:

<script src="script1.js" />
<script src="script2.js" />

Ошибка в script1.js помешает doSomeOtherThing() даже зарегистрироваться, потому что функция $(document).ready() не будет выполнена.

Однако, если script1.js использовал $(document).ready() тоже, этого не произошло бы:

$(document).ready(function() { doSomething(); });
$(document).ready(function() { doSomeOtherThing(); });

Обе строки будут выполнены. Затем цикл событий выполнил бы doSomething, который сломался бы, но doSomeOtherThing не будет затронут.

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


Критика/Вопросы:

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

С нетерпением ждем любых полезных комментариев!

Позднее обновление:

Как правильно указал Briguy37, мое наблюдение, должно быть, было неправильным в первую очередь. ( "Я ошибался - да!" ). Взяв его простой пример, я могу воспроизвести, что во всех основных браузерах и даже в IE8 скрипт2 выполняется, даже если скрипт1 выдает ошибку.

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

4b9b3361

Ответ 1

Ваше первое предположение, что они работают как один script, неверно. Script2 будет выполняться, даже если Script1 выдает ошибку. Для простого теста выполните следующую структуру файлов:

-anyFolder
--test.html
--test.js
--test2.js

Содержимое test.html:

<html>
   <head>
       <script type="text/javascript" src="test.js"></script>
       <script type="text/javascript" src="test2.js"></script>
   </head>
</html>

Содержимое test.js:

console.log('test before');
throw('foo');
console.log('test after');

Содержимое test2.js:

console.log('test 2');

Вывод при открытии test.html(в консоли):

test before test.js:1
Uncaught foo test.js:2
test 2 

Из этого теста вы можете видеть, что test2.js все еще работает, хотя test.js выдает ошибку. Тем не менее, test.js прекращает выполнение после того, как он запустится в ошибку.

Ответ 2

Способ JS обрабатывает ошибки, зависит от того, как JS обрабатывает script. Он не имеет ничего (или мало), чтобы делать с потоками. Поэтому вам нужно сначала подумать о том, как JS работает через ваш код.

Прежде всего, JS будет читать в каждом файле script файл/блок последовательно (в этот момент ваш код просто рассматривается как текст).

Затем JS начинает интерпретировать эти текстовые блоки и компилирует их в исполняемый код. Если обнаружена синтаксическая ошибка, JS прекращает компиляцию и переходит к следующему script. В этом процессе JS обрабатывает каждый script блоки/файлы как отдельный объект, поэтому синтаксические ошибки в script 1 не обязательно нарушают выполнение script 2. Код будет интерпретироваться и скомпилирован, но не выполнен в этот пункт, поэтому команда throw new Error не нарушит выполнение.

После того, как все script файлы/блоки скомпилированы, JS проходит через код (начиная с первого файла кода/блока в вашем коде) и создавая так называемый исполняемый стек (функция функция звонков b вызывает функцию d и c....) и выполнить его в заданном порядке. Если в какой-то момент происходит ошибка обработки или выбрана программно (throw new Error('fail')), все выполнение этого стека прекращается, и JS возвращается к началу в начало этого стека и начинает с выполнения следующего возможного стека.

Тем не менее, причина, по которой ваша функция onload по-прежнему выполняется после ошибки в script1.js, не происходит из-за нового потока или чего-то еще, это просто потому, что событие создает отдельный стек выполнения, JS может перейти к, после того, как произошла ошибка в предыдущем стеке выполнения.

Приступая к вашим вопросам:

Какие существуют причины, из-за которых необходимо немедленно выполнить часть кода, т.е. не обернуть ее в событие?

Я бы посоветовал вам не иметь "незамедлительно" код в вашем веб-приложении. Лучшей практикой является наличие одной точки входа в ваше приложение, которая вызывается внутри события onload

$(document).ready(function () {App.init()});

Это, однако, не имеет никакого отношения к обработке ошибок или тому подобное. Сама обработка ошибок должна обязательно выполняться внутри вашего кода с помощью условных выражений if(typeof myValue !== 'undefined') или блоков try/catch/finally, где вы можете ожидать потенциальных ошибок. Это также дает вам возможность попробовать второй способ внутри блока catch или изящно обработать ошибку в конце.

Если вы можете создать приложение, основанное на событиях (конечно, не для обработки ошибок), сделайте это. JS - это язык, управляемый событиями, и вы можете максимально использовать его, когда записываете управляемый событиями код...

Будет ли это сильно влиять на производительность?

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

Есть ли другой/лучший способ достичь того же, а не использовать событие готовности документа?

Как упоминалось ранее: try/catch/finally

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

Если вы регистрируете одно и то же событие на одном и том же объекте, порядок сохраняется.

Ответ 3

Я не уверен в синтаксических ошибках, но вы можете использовать try {} catch(e) {}, чтобы поймать ошибки и сохранить остальную часть кода.

НЕ запускается до конца

var json = '{"name:"John"'; // Notice the missing curly bracket }

// This probably will throw an error, if the string is buggy
var obj = JSON.parse(json);

alert('This will NOT run');

Будет выполняться до конца

var json = '{"name:"John"'; // Notice the missing curly bracket }

// But like this you can catch errors
try {
  var obj = JSON.parse(json);
} catch (e) {
  // Do or don'
}

alert('This will run');

UPDATE

Я просто хотел показать, как убедиться, что остальная часть кода будет выполнена в случае возникновения ошибки.

Какие существуют причины, необходимые для выполнения части код немедленно, то есть не обертывать его в событие?

Производительность. Каждое такое событие заполняет очередь событий. Не то, чтобы это сильно повредило, но это просто не нужно... Зачем делать некоторые работы позже, если это можно сделать прямо сейчас? Например - обнаружение браузера и прочее.

Будет ли это сильно влиять на производительность?

Если вы делаете это много раз в секунду, тогда да.

Есть ли другой/лучший способ добиться того же, а не использовать готовое событие документа?

Да. См. Пример выше.

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

Да, я уверен, что они есть.