Время выполнения процесса выполнения функции - PullRequest
0 голосов
/ 07 января 2019

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

Но происходит, когда в функции обратного вызова onclick есть несколько функций. Наличие в нем как последовательных, так и асинхронных функций. Затем они снова вернутся к API браузера из стека очереди и вызова, а затем снова к API браузера?

Как выполняется весь приведенный ниже код?

$('#test').on(click, function() {
   console.log('start');

   //modifies the dom like add div in the html
   modifyDom();

   //http ajax call
   someAjaxCall();

   while(let i < 5) {
      console.log(i);
      i++
   }

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


});

Ответы [ 3 ]

0 голосов
/ 16 января 2019

давайте добавим номера строк для отслеживания исполнения

01 $('#test').on(click, function() {
02    console.log('start');
03 
04    modifyDom();
05 
06    someAjaxCall();
07 
08    while(let i < 5) {
09       console.log(i);
10       i++;
11    }
12 
13    setTimeout(
14       function(){
15          console.log('Zero Delay');
16       },
17       0
18    );
19 });
  1. 01: присоединяет обработчик события
  2. дождитесь нажмите ...
  3. нажмите
  4. 02: вывести «start» на консоль
  5. 04: выполнять манипуляции с DOM
  6. 06: отправить запрос ajax и дождаться ответа в сетевом потоке (не в основном потоке)
  7. 08-11
    1. i - это 0
    2. i равно 1
    3. i составляет 2
    4. i составляет 3
    5. i - это 4
  8. 13-18: добавить обратный вызов 14-16 в поток таймера (не основной поток)
  9. ждать, пока потоки вернут управление ...

теперь может произойти любое следующее:

  1. ajax и / или тайм-аут «возврата» до завершения предыдущих выполнений
  2. ajax "возврат" до истечения времени ожидания
  3. тайм-аут "возврата" до ajax

в случае 1 основной поток вообще не заботится о том, что «вернуло», поскольку это единый непрерывный стек синхронных инструкций. это означает, что случай 1 в конечном итоге разрешается в случаях 2 и 3

в случаях 2 и 3, так как обещанные микрозадачи имеют приоритет перед потоками таймера, ajax "return" сначала обещается, а затем происходит обратный вызов тайм-аута


Редактировать 1

Я настоятельно рекомендую смотреть этот доклад на тему основ цикла событий и далее, поскольку он объясняет взаимодействие кода синхронизации, таймеров, обещаний и многого другого

0 голосов
/ 19 января 2019

То, что вы сказали о стеках вызовов и очередях, верно. 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).

0 голосов
/ 07 января 2019

После нажатия на #test вы получите:

  1. console.log('start'); выполняется сразу после ввода обратного вызова
  2. modifyDom() следующий. Он также выполняется синхронно.
  3. someAjaxCall();. Здесь запрос будет отправлен напрямую, тогда его собственный обратный вызов будет обрабатывать ответ, когда он в итоге получит его (асинхронно)
  4. while loop работает синхронно
  5. setTimeout Хотя обычно это выполняется асинхронно (после определенного тайм-аута), вы задали задержку в 0. Таким образом, она будет работать сразу после вызова.
...