setTimeout внутри обещания против setTimeout

javascript #promise #callback

#javascript #обещание #обратный вызов

Вопрос:

Я знаю, что функция обратного вызова внутри setTimeout() будет ждать, пока не истечет срок действия подключенного к ней таймера, и он будет помещен в очередь обратного вызова. С другой стороны, обещание, после выполнения или отклонения, получает обратный вызов, помещенный в очередь микрозадач, которая имеет более высокий приоритет.

Мой вопрос в том, какой раз быстрее: a setTimeout внутри обещания или простой setTimeout . Если первый больше не помещается в очередь микрозадач, почему setTimeout сначала выполняется alone, а не наоборот?

 setTimeout(() => {
  console.log('timeout');
}, 1000);

let promise = new Promise(function(resolve, reject) {
  // This is run automatically, let's run resolve after 1 second
  setTimeout(() => resolve('promise!'), 1000);
});

promise.then(
  (result) => console.log(result),
  (err) => console.log(error)
);

// output: timeout -> promise || and not || promise -> timeout 

Теперь давайте предположим, что я забыл о задержке в 1 секунду, теперь обещание всегда будет отображаться первым, поскольку обратный вызов, запланированный внутри очереди микрозадач, имеет более высокий приоритет

 setTimeout(() => {
  console.log('timeout');
}, 0);

let promise = new Promise(function(resolve, reject) {
  // This is run automatically, let's run resolve after 1 second
  // setTimeout(() => resolve('promise!'), 1000);
  resolve('');
});

promise.then(() => {
  console.log('promise');
}); 

Комментарии:

1. Быстрее? Я бы предположил, что нет абсолютно никакой существенной разницы. Вы все равно ждете целую секунду.

2. Разработка приложения вокруг того, как среда выполнения будет планировать асинхронные события, является крайне плохой идеей. У вас нет гарантии, что время ожидания в любом случае будет особенно близко к 1000 миллисекундам.

3. В обоих случаях сначала должна быть выполнена макрозадача. С обещанием макрозадача приводит к постановке в очередь микрозадачи. Но я не уверен, насколько это вообще полезно.

4. Было бы очень полезно, если бы вы описали проблему, которую пытаетесь решить.

5. @VLAZ прав. В первом коде будет два setTimeout() вызова в очень быстрой последовательности. Среда выполнения поместит их в очередь таймера. Тот, который был запрошен первым, будет запущен первым, а запрошенный второй будет запущен позже. То, что второй setTimeout() вызов находится внутри обратного вызова Promise, не имеет абсолютно никакого значения.

Ответ №1:

setTimeout реализован таким образом, что он предназначен для выполнения после минимальной заданной задержки, и как только поток браузера свободен для его выполнения. итак, для примера, если вы укажете значение 0 для параметра delay и думаете, что он будет выполняться «немедленно», этого не произойдет. он будет, точнее, выполняться в следующем цикле событий (который является частью модели параллелизма цикла событий, которая отвечает за выполнение кода).

Давайте рассмотрим пример для значения задержки 0.

 setTimeout(() => {
  console.log('timeout');
}, 0);

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve('promise!'), 0);
});

promise.then(
  (result) => console.log(result),
  (err) => console.log(error)
); 

setTimeout Всегда сначала регистрируется результат, потому что он обязательно будет выполняться в следующем цикле событий.

С setTimeout другой стороны, в обещании будет 2 цикла событий, пока не будет выполнен журнал консоли (один для разрешения обещания, а другой для обратного вызова в функции setTimeout).

Пожалуйста, прочитайте причину задержек дольше, чем указано — https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified

Подробнее о цикле событий JS — https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop