Javascript setTimeout调用堆栈问题
我在JS中学习了调用堆栈,并自己尝试了一些代码,问题是:Javascript setTimeout调用堆栈问题,javascript,asynchronous,settimeout,Javascript,Asynchronous,Settimeout,我在JS中学习了调用堆栈,并自己尝试了一些代码,问题是: const timestamp = Date.now(); // get current timestamp setTimeout(() => console.log(Date.now() - timestamp), 2000); // get difference Array(10000).fill(0).forEach((item, i) => console.log(i ** 3)); // simulating lon
const timestamp = Date.now(); // get current timestamp
setTimeout(() => console.log(Date.now() - timestamp), 2000); // get difference
Array(10000).fill(0).forEach((item, i) => console.log(i ** 3)); // simulating long-running task
问题是,在我在浏览器中运行代码后,在控制台中记录差异所需的时间要比2000毫秒长得多,可能是4000-6000毫秒,但我的控制台中有2000-2300毫秒。我了解到,setTimeout的计时器在清除调用堆栈后启动,按照这个逻辑,我应该在控制台中获得4000-5000毫秒。
问题是,为什么我得到的是2000-2300毫秒而不是4000-6000毫秒?我不知道是评论还是回答。我认为这可能归结为控制台缓冲区刷新问题。由于要打印这么多控制台行,该函数似乎需要5秒以上的时间才能完成,但实际上只需要2秒,运行超时,并需要6秒才能看到所有控制台的最终结果。尝试从
forEach
中删除console.log
,看看是否仍然可以生成此问题
与其使用变量“long running process”(长时间运行的进程),而不是在everone的计算机上实际长时间运行,不如创建一个示例,明确地在设定的持续时间内阻塞执行线程,看看是否得到相同的结果。我们还要消除控制台缓冲区成为问题的可能性
下面是我在node.js中编写的示例。我不太确定我们如何能够在一个设定的持续时间内可靠地阻止浏览器中的执行线程。由于它对用户体验的影响,我们已经投入了大量的精力来防止这种情况的发生。一个想法可能是在浏览器默认设置后进行一个超时的同步AJAX调用。在任何情况下,使用node我们都可以编写:
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
在整个执行块完成之前,内部增量计算函数永远不会运行。这就是为什么您将差异视为两个参数中较大的一个(乘以1000)
做跨平台阻塞示例的一种方法(比我的更简单)是使用
while
阻塞和日期。现在()
就像在这个问题中做的那样:。事实上,这个问题甚至可以为长时间运行的进程的setTimeout
逻辑提供一些额外的见解:
console.log('Before wait');
setTimeout(函数(){console.log('Yo!');},1000);
var start=Date.now();
而(Date.now()
请记住,您应该避免编写阻塞主JavaScript执行线程的代码,这始终是一个坏主意。如果您需要使用长时间运行的逻辑,请利用。您是说,填充循环将需要2秒以上的时间才能运行?在我10年的MacBook Pro上,是的
console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');