[英]Javascript, Promises and setTimeout
我一直在玩 Promises,但我无法理解以下代码发生了什么:
const promise = new Promise((resolve, reject) => {
console.log('Promise started - Async code started')
setTimeout(() => {
resolve('Success')
}, 10)
})
setTimeout(() => {
console.log('Promise log inside first setTimeout')
}, 0)
promise.then(res => {
console.log('Promise log after fulfilled')
})
console.log('Promise made - Sync code terminated')
setTimeout(() => {
console.log('Promise log inside second setTimeout')
}, 0)
output 是:
Promise started - Async code started
Promise made - Sync code terminated
Promise log inside first setTimeout
Promise log inside second setTimeout
Promise log after fulfilled
正如预期的那样。
但是让我们检查以下代码的 output:
const promise = new Promise((resolve, reject) => {
console.log('Promise started - Async code started')
setTimeout(() => {
resolve('Success')
}, 1)
})
setTimeout(() => {
console.log('Promise log inside first setTimeout')
}, 0)
promise.then(res => {
console.log('Promise log after fulfilled')
})
console.log('Promise made - Sync code terminated')
setTimeout(() => {
console.log('Promise log inside second setTimeout')
}, 0)
将要解决的 promise setTimeout 计时器值从 10ms 更改为 1ms
output 是:
Promise started - Async code started
Promise made - Sync code terminated
Promise log after fulfilled
Promise log inside first setTimeout
Promise log inside second setTimeout
对此有何解释?
setTimeout
在其计时器到期后不会立即运行- 零延迟实际上并不意味着回调将在零毫秒后触发。 以 0(零)毫秒的延迟调用
setTimeout
不会在给定时间间隔后执行回调 function。 基本上,即使您为 setTimeout 指定了特定的时间限制,setTimeout
也需要等待排队消息的所有代码完成。
如果我们设置 2 和 1 毫秒会发生什么:
const promise = new Promise((resolve, reject) => {
console.log('Promise started - Async code started')
setTimeout(() => {
resolve('Success')
}, 2)
})
console.log('Promise log inside first setTimeout 1')
setTimeout(() => {
console.log('Promise log inside first setTimeout 2')
}, 1)
promise.then(res => {
console.log('Promise log after fulfilled ❌')
})
console.log('Promise log inside second setTimeout 1')
setTimeout(() => {
console.log('Promise log inside second setTimeout 2')
}, 1)
});
output 始终为:
Promise started - Async code started
Promise log inside first setTimeout 1
Promise log inside second setTimeout 1
Promise log inside first setTimeout 2
Promise log inside second setTimeout 2
Promise log after fulfilled ❌
如果你想要一个正确的行为,值得摆脱零延迟。
我将使用下面的例子来解释:
setTimeout(() => {
console.log('1 ms timeout');
}, 1); // Moved to async queue at time = T0
setTimeout(() => {
console.log('0 ms timeout')
}, 0); // Moved to async queue after 1 ms that synchronous call to setTimeout takes i.e. at T1
// So at T1, queue will be [("1ms timeout", 0), ("0ms timeout", 0)]
因此这将打印
1 ms timeout
0 ms timeout
上面的理解:调用 setTimeouts 是同步的(即使它的回调放在异步队列中),即我们调用 setTimeout() 并移动到下一条语句 - 这个同步动作本身可能需要 1ms。
换句话说,1ms 太短了,所以当 JS 引擎看到第二个异步语句时,第一个已经在队列中花费了 1ms。
我还建议您尝试以下方法
setTimeout(() => {
console.log("First");
}, 2); // queue at T0 = [("First", 2)]
const forLoopLimit = 100;
for (var i = 0; i < forLoopLimit; i++){
console.log(i * 10000);
} // Assume that it takes about 3 milliseconds
// queue at T3 = [("First", 0)]
setTimeout(() => {
console.log("Second");
}, 0); // Assume it takes 0 milliseconds.
// queue at T4 = [("First", 0), ("Second", 0)]
即使前者的超时时间为 2 毫秒,而后者的超时时间为 0 毫秒,这也会在Second
之前打印First
。 现在将forLoopLimit
更改为 1 甚至 10,您会看到同步任务现在不需要 3 毫秒,并且在First
之前打印了Second
另外值得一试的是:
console.log(Date.now());
console.log(Date.now());
多次尝试以上,你会发现有时控制台日志会有不同的时间戳。 粗略地说,你可以说console.log()
和Date.now()
需要 0.5 毫秒。 只是调用/执行同步内容的时间。
base::TimeDelta interval_milliseconds =
std::max(base::TimeDelta::FromMilliseconds(1), interval);
因此,对于 Chrome,您的所有setTimeout( fn, 0 )
都将转换为setTimeout( fn, 1 )
,因此计划在您安排的第一个之后触发(请记住 Promise 构造函数是同步调用的)。
所以我们实际上可以简化你的例子
setTimeout( () => console.log( '1ms delay' ), 1 ); setTimeout( () => console.log( '0ms delay' ), 0 );
而在 Chrome中, 1ms
延迟总是首先触发,这与常识相反,因为在内部它实际上是:
setTimeout( () => console.log( '1ms delay' ), Math.max(1, 1) ); setTimeout( () => console.log( '0ms delay' ), Math.max(1, 0) );
如果您将其设置为1
和2
而不是0
和1
,您的期望就会得到满足。
const promise = new Promise((resolve, reject) => { console.log('Promise started - Async code started') setTimeout(() => { resolve('Success') }, 2) }) setTimeout(() => { console.log('Promise log inside first setTimeout') }, 1) promise.then(res => { console.log('Promise log after fulfilled') }) console.log('Promise made - Sync code terminated') setTimeout(() => { console.log('Promise log inside second setTimeout') }, 1)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.