Требуется ли setTimeout? - PullRequest
       33

Требуется ли setTimeout?

0 голосов
/ 25 мая 2018

У меня есть вопрос к async, await и setTimeout ().Я думал, я использую асинхронные функции для медленных процессов.Поэтому я попробовал это с большой петлей.На моем компьютере требуется несколько секунд для запуска следующего кода:

function slowFunction() {
    return new Promise(resolve => {
        setTimeout(() => {
            for (let i = 0; i < 4000000000; i++) {};
            resolve('Ready at ' + new Date().toLocaleTimeString('de'));
        }, 0);
    });
};


console.log('Start: ' + new Date().toLocaleTimeString('de'));

(async () => {
    console.log('Call slow function.');
    console.log(await slowFunction());
})();

console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

Вывод:

Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:20
Ready at 16:39:23

А теперь вопрос: в чем отличие следующего кода:

function slowFunction() {
    return new Promise(resolve => {
        for (let i = 0; i < 4000000000; i++) {};
        resolve('Ready at ' + new Date().toLocaleTimeString('de'));
    });
};

console.log('Start: ' + new Date().toLocaleTimeString('de'));

(async () => {
    console.log('Call slow function.');
    console.log(await slowFunction());
})();

console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

Вывод:

Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:23
Ready at 16:39:23

В первом примере это выглядит как асинхронный.Во втором примере функция ожидает окончания цикла.

Нужно ли использовать setTimeout, или в коде есть ошибка, или я ошибаюсь?В обоих случаях определение разрешения находится за большим циклом.

В большинстве примеров асинхронного и ожидающего использования используется setTimeout, но я думаю, это просто для имитации перерыва.

Спасибо за вашу помощьзаранее.

Лучшие приветствия Паскаля

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Разница в том, что это полностью синхронный код:

return new Promise(resolve => {
    for (let i = 0; i < 4000000000; i++) {};
    resolve('Ready at ' + new Date().toLocaleTimeString('de'));
});

Этот оператор заблокирует поток JavaScript и заставит его ждать, пока не пройдут все эти 4 миллиарда итераций. Затем он перейдет к следующему утверждению.Поскольку console.log выполняется после этого, он не будет выполняться, пока этот цикл не завершится.

Вот почему вы видите разницу.

0 голосов
/ 25 мая 2018

TL: DR

Обещания и функции async не переносят ваш код в другой поток.Если вы хотите переместить этот длительный процесс из основного потока, в браузерах посмотрите на веб-работников , а в Node.js посмотрите на дочерних процессов .

Подробности

Обещания и функции async (которые являются всего лишь синтаксисом для создания и использования обещаний) не переносят вашу обработку в какой-либо другой поток, это все равно происходит в том же потоке, в котором вы запускаете процесс.Единственное, что они делают , это обеспечивают асинхронный вызов обратных вызовов then и catch.Они не делают ваш код асинхронным (кроме того, что обратные вызовы происходят асинхронно).

Таким образом, ваш первый блок, использующий setTimeout, просто устанавливает тайм-аут, возвращает обещание, а затем, когда тайм-аутистекает, он блокирует основной поток, пока выполняется медленно работающий процесс.Это просто меняется, когда блокировка происходит немного, это не меняет факт блокировки.

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

function slowFunction() {
  return new Promise(resolve => {
    setTimeout(() => {
      const stop = Date.now() + 2000;
      while (Date.now() < stop) {
        // busy wait (obviously, never really do this)
      }
    }, 1000);
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000);
.as-console-wrapper {
  max-height: 100% !important;
}

Ваш второй блок, не использующий setTimeout, просто блокирует сразу, потому что функция исполнителя обещаний (функция, которую вы передаете new Promise) запускается немедленно и синхронно,и вы ничего не делаете, чтобы сделать это асинхронным.

Вы можете увидеть это здесь;счетчик делает паузу сразу, не позже:

function slowFunction() {
  return new Promise(resolve => {
    const stop = Date.now() + 2000;
    while (Date.now() < stop) {
      // busy wait (obviously, never really do this)
    }
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000);
.as-console-wrapper {
  max-height: 100% !important;
}

Мы даже не видим журнал до slowFunction до тех пор, пока не завершится долгосрочный код, потому что браузер так и не получилшанс перекрасить, у нас была нить захвачена.

Относительно async функций: код в async функции начинается синхронно и является синхронным до первого await(или другая конструкция, такая как setTimeout, которая планирует выполнение вещей позже).Только код после этого является асинхронным (потому что он должен был ждать).

Вот пример, демонстрирующий, что:

async function foo() {
  console.log("before await");
  await Promise.resolve();
  console.log("after await");
}

console.log("before foo");
foo()
  .then(() => {
    console.log("then handler on foo's promise");
  })
  .catch(console.error);
console.log("after foo");

Вот результат этого:

before foo
before await
after foo
after await
then handler on foo's promise

Обратите внимание, как до ожидания происходит до после foo ;это синхронно со звонком на foo.Но тогда после ожидания не происходит позже (потому что await Promise.resolve() должен заставить код, следующий за ним, выполняться асинхронно; это синтаксический сахар для then, который обещает не вызывать свой обработчик синхронно, даже еслиобещание уже выполнено).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...