2016-04-01 4 views
1

У меня есть код Javascript.Понимание порядка выполнения Javascript

var i, _i, _len, _ref; 

_ref = [1, 2, 3]; 
for (_i = 0, _len = _ref.length; _i < _len; _i++) { 
    i = _ref[_i]; 
    setTimeout((function() { 
    return console.log(i); 
    }), 0); 
} 

Это генерируется частью Coffeescript, и именно поэтому в ней странные имена. При выполнении кода выход будет 3 3 3. На основании результата выполнения представляется, что порядок выполнения:

enter for loop 
settimeout 1 with a function 
settimeout 2 with a function 
settimeout 3 with a function 
settimeout 1 execute 
settimeout 2 execute 
settimeout 3 execute 

Это немного отличается с моим пониманием. Как я понимаю, setTimeout в цикле for работает асинхронно. Сам оператор setTimeout может быть выполнен мгновенно. Через несколько миллисекунд (0 в нашем случае) функция начнет выполнение в отдельном контексте. Так что мой ожидаемый порядок исполнения:

enter for loop 
settimeout 1 with a function 
settimeout 2 with a function, settimeout 1 execute 
settimeout 3 with a function, settimeout 2 execute 
settimeout 3 execute 

на основе загрузки процессора и сложности функции передается setTimeout, порядок выполнения может отличаться от того, что я описал выше. Но, на мой взгляд, setTimeout может сразу начать выполнение и не нужно ждать завершения цикла for.

Надеюсь, кто-то может помочь прояснить ситуацию. Я проверяю MDN на setTimeout, но не могу получить ничего полезного.

ответ

1

Лучший способ для меня expain, что меняется понимание того, что любой асинхронный вызов в JavaScript, и setTimeout в частности. Вместо того, чтобы думать о setTimeout как о вызове прямой функции, вы можете рассматривать его как добавление некоторого события в очередь, которое начнет запускать все события только после того, как все остальное будет сделано.

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

В других, более простых словах, setTimeout(..., 0) добавляет какое-то событие onSyncCodeDone.

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

var _ref = [1, 2, 3]; 

function process(index) { 
    if (index < _ref.length) { 
    setTimeout((function() { 
     process(index + 1); 

     return console.log(index); 
    }), 0); 
    } 
} 

process(0); 
+0

Помимо setTimeout и setInterval, могу ли я рассмотреть все остальные синхронные коды? –

+1

нет, все вызовы ajax также асинхронны. В nodejs почти половина функций асинхронна :) – smnbbrv

0

Задача setTimeout будет выполнена после выполнения цикла. потому что это не синхронно. Таким образом, функция внутри setTimeout будет принимать значение i как 3 все время.

Это будет правильный код ...

var i, _i, _len, _ref; 

_ref = [1, 2, 3]; 
for (_i = 0, _len = _ref.length; _i < _len; _i++) { 
    i = _ref[_i]; 
    setTimeout((function(i) { 
    console.log(i); 
    })(i), 0); 
} 
+0

Я знаю правильный код. Я просто пытаюсь понять порядок исполнения. –

+0

Я отредактировал ответ. Надеюсь, это поможет. –

1

Существует идея цикла событий. Несмотря на то, что setTimeout установлен в 0 (он действительно не может опускаться ниже, чем около 14 мс), он по-прежнему помещается в цикл событий. Таким образом, вы ожидаете, что он будет работать мгновенно, но это может не повлиять на то, что еще происходит вне контекста, например, этот цикл работает.

проверьте этот сайт, он взорвет ваш разум и точно, что вам нужно понять.

http://latentflip.com/loupe/

+1

Спасибо, Джеймс, это видео очень полезно! –

1

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

settimeout 2 with a function, settimeout 1 execute 

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

  1. Ваш цикл попадает в очередь и начать
  2. Функция SetTimeout добавляется в очередь после указанного времени, в вашем случае после 0 миллисекунд.
  3. После того, как поток свободен от цикла for, SetTimeouts удаляются из очереди и выполняются.

Вот некоторые ссылки, которые могут быть полезны

http://ejohn.org/blog/how-javascript-timers-work/

http://javascript.info/tutorial/settimeout-setinterval

0

Я здесь simplefied петлю, вы можете увидеть результат здесь: https://jsfiddle.net/TomKarachristos/L6couu2o/

for (_i = 0, _len = 3; _i < _len; _i++) { 
    setTimeout((function() { 
    makeAParagraph(_i); 
    }), 0); 
} 

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

В этом выполнении каждый раз, когда тайм-аут обнаружил, что он вызывает первый параметр (функцию) внутри очереди обратного вызова. Как показано ниже.

Когда циклы заканчиваются, и код для выполнения JavaScript не выполняется, перейдите в очередь обратного вызова, найдите первую функцию и выполните ее. Если это таймаут, сначала проверяется, прошло ли время, когда вы поставили второй параметр, (0 всегда проходит).

Таким образом, первый тайм-аут запускается, когда цикл завершается, и когда это происходит, i равно 3. Здесь у нас есть еще один метод JavaScript с именем закрытия, функция в JavaScript может обращаться к переменным, определенным вне функции. Таким образом, функция внутри таймаута может получить доступ к переменной i снаружи. Но когда первый тайм-аут называется i, это 3, как вы видите на картинке, то же самое со вторым и третьим таймаутом.

enter image description here

Смежные вопросы