Я не знаю, сделать ли это комментарием или ответом. Я думаю, что это может быть связано с проблемой очистки буфера консоли. Может показаться, , что для завершения функции требуется более 5 секунд, потому что она печатает столько консольных строк, но на самом деле это занимает всего ~ 2 секунды, запускает таймаут и ~ 6 секунд, чтобы вы могли увидетьконечный результат всех утешительных. Попробуйте удалить console.log
из forEach
и посмотрите, можете ли вы по-прежнему вызывать эту проблему.
Вместо использования переменной «длительный процесс», которая на самом деле может не работать долго на всех компьютерах,давайте создадим пример, который определенно заблокирует поток выполнения на заданную продолжительность и посмотрим, получим ли мы тот же результат. Давайте также уберем возможность возникновения проблемы с консольным буфером.
Вот мой пример, написанный на node.js . Я не совсем уверен, как мы можем надежно блокировать поток выполнения в браузере на установленную продолжительность. Много усилий было направлено на предотвращение именно этого из-за его влияния на пользовательский опыт. Одной из идей может быть синхронный вызов AJAX, который истекает после браузера по умолчанию. В любом случае, используя узел, мы можем написать:
const {execSync} = require("child_process");
/**
* Test stack/setTimeout interactions
* @param {Number} [t1=5] Duration of setTimeout in seconds
* @param {Number} [t2=5] System sleep duration in seconds
*/
function test(t1=5, t2=5) {
// Get time at start
const start = Date.now();
// Schedule printing of delta
setTimeout(() => {
console.log(`Diff: ${Date.now() - start}`;
}), t1 * 1000);
// Synchronously sleep for a duration
execSync(`sleep ${t2}`);
}
Вот моя выходная матрица:
test(1, 5); // Diff: 5021
test(5, 1); // Diff: 5002
test(3, 3); // Diff: 3018
Внутренняя функция вычисления дельты никогда не запускается, пока не закончится весь блок выполнения. Вот почему вы видите diff как больший из 2 аргументов (умноженный на 1000).
Один из примеров создания примера кросс-платформенной блокировки (это даже проще, чем мой) - использоватьwhile
блок с Date.now()
, как это сделано в этом вопросе: setTimeout поведение с кодом блокировки . Фактически, этот вопрос может даже дать некоторую дополнительную информацию о логике setTimeout
с долго выполняющимися процессами:
console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');
Имейте в виду, что вам следует избегать написания кода, который блокируетосновной поток выполнения JavaScript, , это всегда плохая идея . Если вам нужно использовать длительную логику, используйте WebWorkers .