Автор оригинала: FreeCodeCamp Community Member.
Часто JavaScript только работает. И потому что он написан в читаемом человеке синтаксис, определенные вещи кажется …| интуитивно понятный Но легко игнорировать то, что происходит на более глубоком уровне. В конце концов, хотя это отсутствие понимания приводит к неспособности решить проблему.
Я провожу достаточно времени, пытаясь решить двумерные проблемы, а немного большей частью ее пытаясь решить трехмерные.
Пока мне нравится практиковать кодирование в моем времени, на день я контроллер воздушного движения. Проблемы, которые мы сталкиваемся с воздушным движением, не отличаются от любой другой работы. Существуют рутинные проблемы с рутинными решениями и уникальными проблемами с уникальными решениями. Это через более глубокое понимание, что мы можем решить уникальные.
С снаружи смотрят в воздушном управлении движением, может показаться, что является уникальной проблемой – что существует неотъемлемая необходимая навыка для работы. Однако, в то время как некоторые аптитуды могут упростить изучение любых навыков, в конечном итоге испытывает, что приводит к решению проблем к подсознательному уровню. Результат интуиция.
Интуиция последовала за наблюдением. Соблюдайте уникальную проблему достаточно раз, и это и его решение становятся рутиной. Это замечает согласованность в каждой ситуации, когда мы начинаем развивать ощущение того, что Должен случиться дальше.
Интуиция делает нет, Однако требуют глубокого понимания. Мы часто можем указывать на правильное решение, не имея возможность сформулировать, как или почему он работает. Иногда, однако, мы выбираем решения, которые кажется …| Интуитивно понятные, но на самом деле регулируются незнакомым набором правил.
Что этот код выходит?
for(var i = 1; i < 6; i++) {
setTimeout(function() {
console.log(i);
},1000);
}
console.log('The loop is done!');Найдите некоторое время, чтобы подумать о том, что будет выведен этот код. Мы начнем строить фундамент, чтобы ответить на это, и мы вернемся к этому позже.
JavaScript – это языковой диалект.
Я вырос на северо-восточном Соединенных Штатах. Хотя я говорю по-английски, моя речь несомненно содержит региональный сорт. Этот сорт называется Диалект Отказ Мой конкретный диалект – Реализация (или версия) стандарта английского языка.
Может показаться стандартам рожать диалекты, но это диалект, который изначально управляет необходимостью стандартов. JavaScript похож. JavaScript – это диалект, а не стандарт. Стандарт – Ecmascript , созданный ECMA-европейским ассоциацией производителей компьютеров. Ecmascript – это попытка стандартизировать JavaScript.
Существует более одной реализации ECMAScript, но JavaScript оказывается самым популярным, и, следовательно, имя JavaScript и Ecmascript часто используются взаимозаменяемо.
JavaScript работает в двигателе.
JavaScript – это только текстовый файл. Как водитель без машины, он не может идти очень далеко. Что-то должно запустить или интерпретировать ваш файл. Это делается с помощью JavaScript Engine.
Несколько примеров двигателей JavaScript включают V8, двигатель, используемый Google Chrome; Spidermonkey, двигатель, используемый Mozilla Firefox; И JavaScriptCore, двигатель, используемый Apple Safari. Ecmascript, стандарт языка, обеспечивает согласованность в разных двигателях JavaScript.
Двигатели JavaScript работают в среде.
Пока JavaScript может работать в разных Места (Например, Node.js, популярная технология Server-Side, работает JavaScript и использует тот же двигатель V8, который использует Google Chrome), наиболее распространенным местом для поиска двигателя JavaScript – это веб-браузер.
В браузере двигатель JavaScript – это только одна часть большей среды, которая помогает принести наш код в жизнь. Есть три основные части к этой среде, и вместе они составляют то, что называется среда выполнения Отказ
Стек вызова
Первая часть – это местоположение текущего запущенного кода. Это названо стек вызовов. В JavaScript есть только один стек вызова в JavaScript, и это станет важным, так как мы продолжаем строить наш фонд.
Вот упрощенный пример стека вызовов:
function doSomething() {
//some other code
doSomethingElse();
//some other code
}
function doSomethingElse() {
//some other code
}
doSomething();Начальный стек вызова пуст, так как работает не работает. Когда наш JavaScript Engine наконец достигнет первой вызова функции, dosomething () , это добавляется в стек:
--Call Stack-- doSomething;
Внутри dosomething () Мы запускаем другой код, а затем добраться до DOSOMOTLETHELTELSE ():
--Call Stack-- doSomething doSomethingElse
Когда DOSOMOTLETHELDELSE () Готован работает, он удален из стека вызова:
--Call Stack-- doSomething
Наконец, dosomething () Заканчивает оставшийся код и также удален из стека вызовов:
--Call Stack-- Empty
Web API
Вторая часть нашей среды браузера наполняет несколько пустот. Удивительно, что такие вещи, как взаимодействие с DOM, изготовление серверов, и большинство задач на основе браузера – не Часть стандарта языка Ecmascript.
К счастью, браузеры предлагают нам дополнительные функции, которые можно подключить наш двигатель JavaScript. Эти функции расширяют функциональность JavaScript в браузере. Они позволяют нам делать такие вещи, как слушать события или сделать серверные запросы – вещи, которые JavaScript не могут сделать сам по себе. И они называются w EB API Отказ
Многие веб-API позволяют нам слушать или ждать чего-то возникшего. Когда произойдет это событие, мы тогда запустим какой-то другой код.
Вот наш пример стека вызовов расширен, чтобы включить (притворяться) веб-API.
function doSomething() {
//some other code
listenForClick();
doSomethingElse();
//some other code
}
function doSomethingElse() {
//some other code
}
listenForClick() {
console.log('the button was clicked!')
}
doSomething();Когда браузер встречает dosomething () Он размещен в стеке вызовов:
--Call Stack-- doSomething
Затем он запускает какой-то другой код, а затем встречает Слушай, пожалуйста, (...) :
--Call Stack-- doSomething listenForClick
Слушай, что () Включается в веб-API, а в этом случае он удаляется из нашего стека вызовов.
Двигатель JavaScript теперь перемещается на DOSOMOTLETHELDELSE () :
--Call Stack-- doSomething doSomethingElse
DOSOMOTLETHELDELSE () и dosomething () Готово, и стек вызова пуст. Но что случилось с Слушай, что () ?
Очередь событий
Здесь мы вводим окончательную часть нашей среды браузера. Часто наш код Web API – это функция, которая принимает обратный вызов. Обратный вызов – это просто какой-то код, который мы хотим запустить после другой функции. Например, прослушивание события клики, а затем console.log что-то. Чтобы убедиться, что наш console.log Не вмешивается в любой текущий код, который сначала проходит к чему-то, называемую Очередь события Отказ
Очередь события действует как зона ожидания, пока наш стек вызова не будет пустым. После того, как стек вызовов пуст, очередь события может пройти наш код в стек вызовов для запуска. Давайте продолжим строить на нашем предыдущем примере:
function doSomething() {
//some other code
listenForClick();
doSomethingElse();
//some other code
}
function doSomethingElse() {
//some other code
}
listenForClick() {
console.log('the button was clicked!')
}
doSomething();Так что теперь наш код работает так:
Наш двигатель встречает dosomething () :
--Call Stack-- doSomething
dosomething () Запускает некоторый код, а затем встречает Слушай, пожалуйста, (...) Отказ В нашем примере это принимает обратный вызов, который является кодом, который мы хотим запустить после того, как пользователь нажимает кнопку. Двигатель проходит Слушай, пожалуйста, (...) из стека вызовов и продолжается до тех пор, пока он не сталкивается с DOSOMOTLETHELDELSE () :
--Call Stack-- doSomething doSomethingElse
DOSOMOTLETHELDELSE () Запускает некоторый код и заканчивается. К этому времени наш пользователь нажимает кнопку. Веб-API слышит Нажмите и отправляет console.log () Заявление на очередь событий. Мы притворяемся dosomething () не сделано; Поэтому стек вызовов не пуст, а console.log () Заявление должно подождать в очереди события.
--Call Stack-- doSomething
Через несколько секунд dosomething () заканчивается и удаляется из стека вызовов:
--Call Stack-- EMPTY
Наконец, console.log () Заявление может быть передано в стек вызова для выполнения:
--Call Stack--
console.log('The user clicked the button!')Имейте в виду, наш код работает невероятно быстро – принимая однозначные миллисекунды для завершения. Это не реалистично, мы могли бы запустить наш код, и наш пользователь мог нажать кнопку до того, как код будет запущен. Но в нашем упрощенном примере мы притворяемся, что это правда, выделить определенные концепции.
Вместе все три части (стек вызовов, веб-API и очередь событий) формируют то, что называется моделью параллелизма, с помощью Структура событий Управление кодом, который идет из очереди событий в стек вызова.
Выполнение из приведенных выше примеров:
JavaScript может сделать только одну вещь за раз.
Существует неправильное представление о том, что люди могут многократно. Это не верно. Люди могут, однако, переключаться между задачами, процесс называется Задача переключения Отказ
JavaScript похож в том смысле, что он не может многозадачить. Поскольку JavaScript имеет только один стек вызовов, двигатель JavaScript может выполнять только одну задачу одновременно. Мы говорим, что это делает JavaScript Одиночная резьба Отказ В отличие от людей, однако, JavaScript не может задавать переключатель без помощи наших веб-API.
JavaScript должен закончить задачу, прежде чем двигаться дальше.
Поскольку JavaScript не может переключаться взад-вперед между задачами, если у вас есть какой-либо код, который занимает некоторое время для запуска, он заблокирует следующую строку кода. Это называется Блокирующий код , и это происходит, потому что JavaScript это Синхронный Отказ Синхронные просто означает, что JavaScript должен закончить задачу, прежде чем она сможет начать другую.
Примером блокирующего кода может быть запрос на сервер, который требует от нас дождаться возвращения данных. К счастью, веб-API, предоставленные браузером, дают нам путь вокруг этого (с использованием обратных вызовов).
Перемещение блокирующего кода из стека вызовов в контуру события, наш двигатель может перейти к следующему элементу в стеке вызовов. Следовательно, с кодом, работающим в нашем стеке вызовов, а код, который одновременно работает в веб-API, у нас есть Синхронный поведение.
Однако не все веб-API, вошли в петлю событий. Например, console.log Это веб-API, но так как не имеет обратного вызова и не нужно ничего ждать, оно может быть выполнено немедленно.
Имейте в виду, что одиночная резьба не совпадает с синхронным. Одиночные резьбовые средства «одна вещь за раз». Синхронные средства «финишировать, прежде чем двигаться дальше». Без помощи асинхронных API, Core JavaScript – это как отдельная резьба, так и синхронная.
Совок по объему
Прежде чем мы вернемся к нашему оригинальному вопросу, нам нужно коснуться по объему. Область применения – это термин, используемый для описания, какие части нашего кода имеют доступ к которым переменные.
Интуитивно, может показаться, что переменная объявлена и инициализирована на для петли будет доступно только в том числе для петли Отказ Другими словами, если вы пытались получить доступ к нему за пределами цикла, вы получите ошибку.
Это не так. Объявление переменной с var Кловое слово создает переменную, которая также доступна в его родительской области.
В этом примере показано, что переменная объявлена var в пределах для петли Также доступен в родительской области (в этом случае глобальный объем).
for(var a = 1; a < 10; a++) {} // declared "inside" the loop
console.log(a); // prints "10" and is called "outside the loop"Ответ показал
На данный момент мы обсуждали достаточно, чтобы построить наш ответ.
Вот наш пример отсматривается:
for(var i = 1; i < 6; i++) {
setTimeout(function() {
console.log(i);
},1000);
}
console.log('The loop is done!');Интуитивно, вы можете поверить, что это напечатает числа на один по пять, одна секунды между каждым числом печатается:
// one second between each log 1 2 3 4 5 The loop is done!
Однако то, что мы на самом деле вывод:
The loop is done! // then about one second later and all at once 6 6 6 6 6
Что происходит?
Напомним наше обсуждение Web API. Асинхронные веб-API или те, которые с обратными вызовами проходят через петлю события. Setimeout () Бывает асинхронной веб-API.
Каждый раз, когда мы петлю, Setimeout () пропускается за пределами стека вызовов и входит в цикл события. Из-за этого двигатель способен переходить на следующий кусок кода. Следующий кусок кода бывает остальными итерациями петли, а затем console.log ('loop сделано!') Отказ
Показать Setimeout () С заявлениями передаются из стека вызовов, а цикл работает, мы можем разместить console.log () заявление за пределами Setimeout () функция и распечатать результаты. Мы также можем разместить встроенный метод таймера, чтобы показать, насколько быстро все происходит. Мы используем Консоль. Время () и Console.Timeend () сделать это .
console.time('myTimer');
for(var i = 1; i < 6; i++) {
console.log('Loop Number' + i); // added this
setTimeout(()=>{
console.log(i);
},1000);
}
console.log('The loop is done!');
console.timeEnd('myTimer');Результаты:
Loop Number 1 Loop Number 2 Loop Number 3 Loop Number 4 Loop Number 5 The loop is done! // then, about one second later and all at once: 6 6 6 6 6 myTimer: 1.91577ms // Wow, that is quick!
Во-первых, мы можем видеть, что цикл на самом деле работает. Кроме того, таймер, который мы добавили, говорит нам, что все, кроме нашего Setimeout () Функции потребовали меньше двух миллисекунд! Это означает, что каждый Setimeout () Функция имеет около 998 миллисекунд, оставшихся до того, как код, который он содержит, переходит в очередь событий, а затем, наконец, в стек вызова. Помните ранее, когда я сказал, что пользователю будет сложно быть быстрее, чем наш код!
Если вы запускаете этот код несколько раз, вы, вероятно, заметите, что вывод таймера немного изменится. Это связано с тем, что доступные ресурсы вашего компьютера всегда меняются, и каждый раз может быть немного быстрее или медленнее.
Так вот что происходит:
- Наш двигатель наткнулся на нашу петлю. Мы объявляем и инициализируем глобальную переменную с именем
Яравный одному. - Каждая итерация петлей проходит
Setimeout ()на веб-API и в контур событий. Поэтому нашедля петлиЗаканчивается очень быстро, поскольку внутри него нет другого кода. На самом деле, единственное, что нашу петлю делает изменение стоимостиЯдо шести. - На данный момент цикл окончен, наш
Setimeout ()Функции все еще подсчитываются, и все, что остается в стеке вызовов, этоconsole.log ('loop сделано!')Отказ - Быстро вперед немного, и
Setimeout ()Функции закончили, аconsole.log (i)заявления идут в очередь событий. К этому времени нашconsole.log ('loop сделано!')был напечатан, и стек вызова пуст. - Так как стек вызова пуст, пять
console.log (i)Заявления передаются из очереди событий в стек вызова. - Помните,
ЯСейчас равен шести, и именно поэтому мы видим пять шестерс, напечатанных на экран.
Давайте создадим вывод, который мы думали, что мы получим
До этого момента мы обсуждали фактический Вывод нескольких простых строк кода, который оказался не так просто. Мы говорили о том, что происходит на более глубоком уровне, а результат. Но, что, если мы хотим создать вывод, мы думал Мы бы получили? Другими словами, как мы можем обратить инженеров следующих результатов:
1 // after one second, then 2 // one second later (2 seconds total) 3 // one second later (3 seconds total) 4 // one second later (4 seconds total) 5 // one second later (5 seconds total) 'The loop is done!' // one second later (6 seconds total)
Продолжительность на нашем тайм-ауте времени меняет что-нибудь?
Установка продолжительности Time out до нуля кажется возможным решением. Давайте попробуем.
for(var i = 1; i < 6; i++) {
setTimeout(()=>{
console.log(i);
},0);
}
console.log('The loop is done!');Результаты:
// Everything appears (essentially) at once The loop is done! 6 6 6 6 6
Это все еще не сработало. Что произошло?
Помните, только потому, что продолжительность Setimeout () равен нулю, он все еще асинхронный и обрабатывается веб-API. Независимо от продолжительности, он будет передан в очередь событий, а затем стек вызова. Так что даже при тайм-ауте в нулевом процессе остается прежним, а выход относительно без изменений.
Обратите внимание, я сказал относительно Отказ Одна вещь, которую вы, возможно, заметили, что это было разным, все напечатано почти однажды. Это потому, что продолжительность Setimeout () Истекает мгновенно, и его код попадает из веб-API в очередь события, и, наконец, в стек вызовов почти сразу. В нашем предыдущем примере наш код должен был подождать 1000 миллисекунд до того, как он вошел в очередь событий, а затем стек вызова.
Итак, если изменение продолжительности до нуля не работала, теперь что?
Ревесивающая область
Что будет этот код?
function myFunction1() {
var a = 'Brandon';
console.log(a);
}
function myFunction2() {
var a = 'Matt';
console.log(a);
}
function myFunction3() {
var a = 'Bill';
console.log(a);
}
myFunction1()
myFunction2()
myFunction3()Обратите внимание, как каждая функция использует одну и ту же переменную, названную А Отказ Казалось бы, кажется каждая функция может бросить ошибку или, возможно, перезаписать значение А Отказ
Результаты:
Brandon Bill Matt
Там нет ошибок, а А уникален каждый раз.
Похоже, что переменная А уникален для каждой функции. Это очень похоже на работу адреса. Названия улиц и цифры неизменно поделится по всему миру. Существует более одного 123 главного ул., Это город и государство, которое предоставляет Область к какому адресу принадлежит где.
Функции работают так же. Функции действуют как защитный пузырь. Что-нибудь внутри этого пузыря не может быть доступен на улицу. Вот почему переменная А на самом деле не то же самое Переменная. Это три разные Переменные, расположенные в трех разных местах в памяти. Они просто так случится со всеми, что разделяют одно и то же имя.
Применение принципов масштаба на нашем примере:
Мы знаем, что имеем доступ к итеративному значению Я , просто не когда Setimeout () Заявления отдела. Что если мы возьмем ценность Я и упаковать его с Setimeout () Заявление в собственном пузыре (как способ сохранить I )?
for(var i = 1; i < 6; i++) {
function timer(){ // create a unique function (scope) each time
var k = i; // save i to the variable k which
setTimeout(()=>{
console.log(k);
},1000);
}
timer();
}Результат:
The loop is done! 1 2 3 4 5
Это почти работает. Что мы сделали?
Мы начинаем попасть в тему закрытие. Глубокое обсуждение на закрытиях выходит за рамки этой статьи. Тем не менее, краткое введение поможет нашему пониманию.
Помните, каждая функция создает уникальный объем. Из-за этого переменные с тем же именем могут существовать в отдельных функциях и не мешать друг другу. В нашем последнем примере каждая итерация создала новую и уникальную область (вместе с новой и уникальной переменной k ). Когда для петли сделано, эти пять уникальных значений к все еще в памяти и доступны соответствующим образом нашими console.log (k) заявления. Это закрытие в двух словах.
В нашем оригинальном примере, где мы объявляем Я с var Каждая итерация перезагружает значение Я (который в нашем случае была глобальная переменная).
ES6 делает это намного чище.
В 2015 году Ecmascript выпустил основное обновление его стандартам. Обновление содержало много новых функций. Одной из этих функций было новым способом объявления переменных. До этого момента мы использовали var Ключевое слово для объявления переменных. ES6 представил Пусть ключевое слово.
for(let i = 1; i < 6; i++) {
setTimeout(()=>{
console.log(i);
},1000);
}
console.log('The loop is done!');Результаты:
The loop is done! 1 2 3 4 5
Просто изменив var к Пусть Мы намного ближе к результату, которое мы хотим.
Краткое введение в «Пусть» vs “var”
В нашем примере Пусть делает две вещи:
Во-первых, это делает Я Доступно только внутри нашего для цикла. Если мы попытаемся войти Я Снаружи цикла мы получаем ошибку. Это потому, что Пусть является переменным блочным объемом. Если он находится внутри блока кода (например, A для петли ) его можно добраться только там. var Является функцией Scoped.
Пример, чтобы показать Пусть против var поведение:
function variableDemo() {
var i = 'Hello World!';
for(let i = 1; i < 3; i++) {
console.log(i); // 1, 2, 3
}
console.log(i); // "Hello World!"
// the for-loop value of i is hidden outside of the loop with let
}
variableDemo();
console.log(i); //Error, can't access either value of iОбратите внимание, как у нас нет доступа к либо Я Снаружи функции VARIABLEMO () Отказ Это потому, что «Hello World» Функция не хватает, а Я это блок.
Вторая вещь Пусть Для нас создает уникальное значение Я Каждый раз, когда петли итерат. Когда наш цикл закончится, мы создали шесть отдельных значений Я которые хранятся в памяти, что наше console.log (i) Заявления могут получить доступ. С Вар, У нас была только одна переменная, которую мы продолжали перезаписать.
Петля не сделана.
Мы почти там. Мы все еще регистрируем «Векл сделан!» Во-первых, и мы не возобновляем все вторым друг от друга. Во-первых, мы рассмотрим два способа решить Цикл сделан! выход.
Вариант 1: Использование SettimeOut () и модели параллелизма в наше преимущество.
Это довольно просто. Мы хотим Цикл сделан! пройти через тот же процесс, что и console.log (i) заявления. Если мы обертываем Цикл сделан! в оформлении Setimeout () Чья продолжительность больше или равна, чем для петли Тайм-ауты, мы гарантируем Цикл сделан! прибывает позади и истекает после последнего для петли тайм-ауты.
Мы немного раскроем наш код, чтобы сделать его немного понятным:
function loopDone() { // we will call this below
console.log('The loop is done!)'
}
for(let i = 1; i < 6; i++) {
setTimeout(()=>{
console.log(i);
},1000);
}
setTimeout(loopDone, 1001);Результаты:
1 2 3 4 5 The loop is done!
Вариант 2: Проверьте наличие окончательного завершения Console.log (i)
Другой вариант – проверять, когда console.log (i) заявления сделаны.
function loopDone() {
console.log('The loop is done!');
}
for(let i = 1; i < 6; i++) {
setTimeout(()=>{
console.log(i);
if(i === 5){ // check when the last statement has been logged
loopDone();
}
},1000);
}Результаты:
1 2 3 4 5 The loop is done!
Обратите внимание, что мы разместили нашу проверку завершенной петли в Setimeout () Функция, не в основном корпусе для цикла.
Проверка, когда петля сделана, не поможет нам, так как мы все еще должны дождаться тайм-аута для завершения. Что мы хотим сделать, это проверить, когда console.log (i) заявления сделаны. Мы знаем, что это будет после Значение Я 5 и после Мы вошли в систему. Если мы разместим нашу проверку завершенной петли после оператора Console.log (i), мы можем убедиться, что мы регистрируем окончательный Я до Мы бежим Loopdone () Отказ
Получить все, чтобы выполнить одну секунду.
Все происходит по существу одновременно, потому что цикл настолько быстрая, и все тайм-ауты прибывают на веб-API в пределах миллисекунды друг друга. Поэтому они истекают примерно в одно и то же время и идут в очередь событий и называть стек примерно в то же время.
Мы не можем легко изменить, когда они прибудут на веб-API. Но мы можем, с уникальной ценностью каждого Я Задержка, как долго они остаются там.
function loopDone() {
console.log('The loop is done!');
}
for(let i = 1; i < 6; i++) {
setTimeout(()=>{
console.log(i);
if(i === 5){
loopDone();
}
},i * 1000); // multiple i by 1000
}С Я сейчас уникален (потому что мы используем Пусть ), если мы умножим Я К 1000 году каждый тайм-аут будет длиться секунду дольше, чем предыдущий тайм-аут. Первый тайм-аут прибудет с длительностью 1000 миллисекунд, второй с 2000 и так далее.
Хотя они приходят в то же время, теперь он будет предпринять каждый тайм-йOU на одну секунду дольше, чем предыдущий, чтобы перейти к очереди события. Поскольку на нашем стеке вызовов пуст на данном этапе, он немедленно идет от очереди событий сразу в стек вызова для выполнения. С каждым console.log (i) Заявление, прибывающее в одну секунду, кроме очередной в очереди, мы будем почти есть наш желаемый выход.
1 // after one second, then 2 // one second later (2 seconds total) 3 // one second later (3 seconds total) 4 // one second later (4 seconds total) 5 // one second later (5 seconds total) 'The loop is done!' // still occurs with the final log
Обратите внимание, что Цикл сделан! все еще прибывает с последний console.log (i) Заявление, не в одну секунду после этого. Это потому, что когда I === 5 Loopdone () бежит Это печатает как Я и Цикл сделан! заявления примерно в то же время.
Мы можем просто обернуть Loopdone () в оформлении Setimeout () обратиться к этому.
function loopDone() {
console.log('The loop is done!');
}
for(let i = 1; i < 6; i++) {
setTimeout(()=>{
console.log(i);
if(i === 5){
setTimeout(loopDone, 1000); // update this
}
},i * 1000);
}Результаты:
1 // after one second, then 2 // one second later (2 seconds total) 3 // one second later (3 seconds total) 4 // one second later (4 seconds total) 5 // one second later (5 seconds total) 'The loop is done!' // one second later (6 seconds total)
У нас наконец-то есть результаты, которые мы хотели!
Большая часть этой статьи произошла от моей собственной борьбы и последующего ага! Моменты в попытке понять замыкание и петлю событий JavaScript. Я надеюсь, что это может почувствовать смысл основных процессов в игре и служить основой для более продвинутых дискуссий по теме.
Спасибо!
ворота