Как работает асинхронщина?

Пример

function async() {
  setTimeout(function() {
    console.log('async')
  }, 0);
}

function norm(){
  console.log('norm')
}

// вызываю

async(); // asynс 1
async(); // asynс 2
async(); // asynс 3

norm(); // norm 1

async(); // asynс 4

norm(); // norm 2

Как понимаю работу асинхронщины Я -

  1. интерпретатор приходит к строке “// async 1” понимает что это асинхронщина и закидывает к себе в стек асинхронщины и пошел дальше

  2. пришел к “// async 2” и ее в стек асинхронщины

  3. пришел к “// async 3” и ее туда же в стек асинхронщины

  4. теперь нашел norm() “// norm 1” и тут же выполняет ее
    После этого я ожидал что он выполнит одну или все три асинхронные функции из стека, но взамен, как я понимаю, интерпретатор дабавляет в асинхронный стек (где все еще 3 функции) " // asynс 4", после выполняет “// norm 2” и только потом прогоняет асинхронный стек
    Почему в этом примере синхронные и асинхронные функции отрабатывают именно в такой последовательности и будут такие логи

    norm
    norm
    async
    async
    async
    async
    ?

Еще заметил что setTimeout/setInterval возвращают свое id еще не начавщись, т. е.

var id = setTimeout(function(){
  console.log('setTimeout')
}, 5000);
console.log('id', id)

Выводит айди еще не выполненного таймера.
Очень крутая уловка

Почему в этом примере синхронные и асинхронные функции отрабатывают именно в такой последовательности и будут такие логи

Интерпретатор выполнит все “неасинхронные” функции из основного потока, а потом выполнит пачкой очередь таймеров.

Еще заметил что setTimeout/setInterval возвращают свое id еще не начавщись

По идее при инициализации присваиваются эти id. А выполнение - откладывается.

По факту да, но я спрашиваю “Почему?”, ведь в таймере стоит 0 и после

// norm 1

по идее должны быть выполненны первые три асинхронные функции

// asynс 1
// asynс 2
// asynс 3

Хорошо, если у нас случай когда функций куча и они выполняются скажем 3.5 сек, а таймер установлен первой строкой в .js файле с задержкой 1 сек, тогда нам стоит ждать что по истечению 1 сек закончится выполнение последней “синхронной” функции и после нее так же синхронно выполнится таймер, верно?

А время не играет роли. Важно - все ли функции из основного потока выполнены.
Парсер идёт построчно вниз по коду и собирает таймеры в конец очереди. И в конце - выполняет их.

Что занчит[quote=“YozhEzhi, post:4, topic:1376”]
функции из основного потока выполнены.
[/quote]

?

И что же, если я ставлю таймер в глобальной видимости то он сработает после всех функций?

Ответил выше.

В конце строки или в конце этого непонятного “основного потока”?
А что это за поток?

Порядок обработки событий

Отложенный вызов через setTimeout(func, 0) используется не только в событиях, а вообще – всегда, когда мы хотим, чтобы некая функция func сработала после того, как текущий скрипт завершится.

Не убедил)

Сама статьяне полностью открывает ответ, в 1м коментарии хорошее объеснение с дополнением видео где исчерпывающе объясняется принцип работы асинхронного кода
YozhEzhi спасибо, вопрос закрыт

Мое понимание - задержка в 0 говорит о том что выполнить операцию нужно сразу же, но в следующий свободный тик. А это понятие относительное и варьируется. Думаю на больших объемах вычислений с циклами и отложенными (асинхронными) операциями можно лучше прочувствовать когда этот свободный тик произойдет для интерпретатора.

Идентификатор ты получаешь сразу, иначе ты не смог бы почистить таймаут или интервал, если передумал запускать его.

Да, выполнение отложиться, но не на следующий свободный “чих”(кстати что это за чих такой?) а в стек-очередь для асинхронных функция, которая выполняется по завершению всех синхронных действий
Вот хороший доклад о выполнении асинхронного кода

2 лайка

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

Пример:

// планируем отложенное действие
setTimeout(function() {
    console.log('async fired!');
}, 0); // выполняем с нулевой задержкой - как можно быстрее

for (var i = 0; i < 1000; i += 1) { // выполняем кучу синхронного кода
    console.log('Processing item:' + i); // асинхронный в него не сможет влезть
}

console.log('all done'); // синхронный закончился

На выходе будем иметь:

Processing item:0
...
Processing item:998
Processing item:999
all done
async fired!

Асинхронный подъехал черти когда, хотя просили побыстрее. Прямо как полиция ) Можно хоть миллиард итераций в цикле поставить, все равно асинхрон не стрельнет раньше.

2 лайка

да есть такое