[英]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.