То, что вы сказали о стеках вызовов и очередях, верно. JavaScript выполнит весь синхронный код и добавит асинхронные вызовы в очередь. setTimeout
объявляет, когда оно может быть выполнено заранее. Если в очереди нет ожидающих задач, она будет вызвана после того, как стек вызовов будет очищен за предоставленное минимальное время, которое в этом случае равно нулю. Аргумент задержки для setTimeout
не гарантирует, что он будет выполнен в это время, но является минимальным значением, когда это возможно. Это связано с тем, что в очереди существуют элементы, которые необходимо сначала очистить, прежде чем это можно будет обработать.
Обработчики событий для сетевых вызовов, такие как ваша функция someAjaxCall
, также являются обратными вызовами. Слушатели вызова Ajax в основном ожидают и не добавляются в очередь до тех пор, пока не произойдет соответствующее событие (например, progress
, error
или success
). Тем не менее они точно такие же, как setTimeout
и будут вызывать обратный вызов через очередь.
Одна вещь, которая может помочь немного прояснить это, это синтаксис async
и await
. Объявляя вашу функцию асинхронной, вы можете лучше обрабатывать асинхронные задачи в вашем рабочем процессе. Например, если вам нужно обработать вызов Ajax перед продолжением, вы можете сделать что-то вроде этого:
// declaring function with async tag
$('#test').on(click, async function() {
console.log('start');
//modifies the dom like add div in the html
modifyDom();
//http ajax call
try {
let response = await someAjaxCall();
console.log('data!', response);
} catch(err){
console.log('network error!', err);
}
while(let i < 5) {
console.log(i);
i++
}
setTimeout(function(){ console.log('Zero Delay'); },0);
});
function someAjaxCall(){
return new Promise((resolve, reject) => {
$.ajax({
url:'someUrl',
type:'GET',
success:function(response){
resolve(response);
},
error:function(err){
reject(err);
}
})
})
}
В этом примере функция while ожидает ответа someAjaxCall
в блоке try / catch. Выполнение остальной части функции задерживается до тех пор, пока эта функция не разрешит или не отклонит. С этой настройкой вы увидите этот выход:
// start
// either 'data!', with the {response} or 'network error!', with the {error}
// 1
// 2
// 3
// 4
// 5
/*
call stack has ended
the function will return undefined because there is nothing being returned
all queues are assessed from oldest to youngest.
only the setTimeout is in the queue so it's callback is executed
*/
//'Zero Delay'
Обновление
Кроме того, если вам нужно измерить время, необходимое для выполнения вашей функции, вы можете использовать console.time
и console.timeEnd
(документация здесь ). Добавив console.time
с некоторой меткой, такой как console.time('Click time')
в начале вашей функции, вы можете добавить console.timeEnd('Click time')
в другую позицию, чтобы точно узнать, сколько времени потребовалось, чтобы пробежать между этими точками (как в начале функции щелчка до обратного вызова setTimeout
).