Javascript、承诺和设置超时
我一直在玩弄承诺,但我很难理解以下代码发生了什么:Javascript、承诺和设置超时,javascript,google-chrome,promise,settimeout,es6-promise,Javascript,Google Chrome,Promise,Settimeout,Es6 Promise,我一直在玩弄承诺,但我很难理解以下代码发生了什么: const promise = new Promise((resolve, reject) => { console.log('Promise started - Async code started') setTimeout(() => { resolve('Success') }, 10) }) setTimeout(() => { console.log('Promise log inside
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)
输出为:
Promise started - Async code started
Promise made - Sync code terminated
Promise log inside first setTimeout
Promise log inside second setTimeout
Promise log after fulfilled
Promise started - Async code started
Promise made - Sync code terminated
Promise log after fulfilled
Promise log inside first setTimeout
Promise log inside second setTimeout
正如所料
但让我们检查以下代码的输出:
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)
将要解析的承诺设置超时计时器值从10ms更改为1ms
输出为:
Promise started - Async code started
Promise made - Sync code terminated
Promise log inside first setTimeout
Promise log inside second setTimeout
Promise log after fulfilled
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
需要等待队列消息的所有代码完成,即使您指定了特定的时间限制 为您的设置超时setTimeout
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)
});
输出始终为:
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
对上述内容的理解:
调用setTimeout是同步的(即使它的回调被放在异步队列中),也就是说,我们调用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)]
多次尝试上面的内容,您会发现有时候控制台日志会有不同的时间戳。大致上,您可以说console.log()
和Date.now()
需要0.5ms。现在是调用/执行同步的时候了
因此,对于Chrome,所有setTimeout(fn,0)
都会转换为setTimeout(fn,1)
,并计划在您计划的第一个之后触发(请记住,承诺构造函数是同步调用的)
所以我们可以用
setTimeout(()=>console.log('1ms delay'),1);
setTimeout(()=>console.log('0ms delay'),0)代码>。在这种情况下,不同的浏览器(JavaScript引擎)表现不同。看起来Chrome无法区分非常小的延迟和0
。可能的重复。1
被视为是0
,在这种情况下,日志又开始有意义了。@Bergi它实际上是0
,在Chrome中被视为1
。但这仍然不能解释为什么1ms超时被安排在0ms之前触发,即使执行回调之前发生的事情需要很长时间,它们应该先安排0毫秒,然后安排1毫秒,就像你的1和2示例一样,这很可能不会在计划完成后1和2毫秒触发。1ms调用setTimeout?认真地Nhaa,你可能在一个非常幸运的日子,你在T00:00:00.00999给第一个打电话。。。第二个是T:00:00:00.0100,但仅此而已,不是确定性行为,而是随机行为。