如題,之前有看過某篇文章提到在useEffect裡調用setTimeout,並使用陣列做forEach的console.log,在瀏覽器console看到的顯示是陣列全部跑完的解果,而不是forEach順序依照秒數去延遲顯示該index的內容,程式碼如下:
const arr1 = [1, 2, 3, 4, 5];
const loopShow = () => {
arr1.forEach((n) => {
setTimeout(() => {
console.log(n);
}, 3000);
});
};
useEffect(() => {
loopShow();
}, []);
上面程式碼我在瀏覽器console看到的是如下圖:
console.log 1~5是3秒後直接一次炸出來,不是每過三秒顯示下一個數字這樣。
之前有看的某個文章有講解這個問題,但因為工作上一直沒用到相關的功能就沒特別去記,現在想嘗試新東西卻剛好遇到,還請求大大們幫助解惑!
如果想直接看 code 的話,你的需求應該要使用 for(){await new Promise}
,或是再自己寫一個 asyncForEach
來使用。
const arr1 = [1, 2, 3, 4, 5]
const loopShow = async () => {
for (const n of arr1) {
await new Promise((resolve) => {
setTimeout(() => {
console.log(n)
resolve(n)
}, 3000)
})
}
}
loopShow()
Array.prototype.asyncForEach = async function (callback) {
for (let i = 0; i < this.length; i++) {
await callback(this[i], i, this)
}
}
const arr1 = [1, 2, 3, 4, 5]
const loopShow = () => {
arr1.asyncForEach(async (n) => {
await new Promise((resolve) => {
setTimeout(() => {
console.log(n)
resolve(n)
}, 3000)
})
})
}
loopShow()
感謝大大!!原來是我沒搞懂JS的非同步,剛研究您給的文章終於瞭解了!
認真來說,這與你使用useEffect並不是直接的關係。
首先你要了解 setTimeout 的特性。
而不是用自已的感覺。
省先簡單先用如下單純的程式碼說明
var n=0;
setTimeout(() => {
console.log(n)
n++
}, 3000)
setTimeout(() => {
console.log(n)
n++
}, 3000)
setTimeout(() => {
console.log(n)
n++
}, 3000)
這邊你可能會誤以為,每一段都先跑3秒後再運行。
其實不然。
上面的程式是設定了3個計時3秒後秀出console
也就是說,在3秒後會一口氣3個全部秀出。
那就回來你的程式碼來看。你是用了 forEach
forEach並不會等待。也就是說,其實跟我上面的寫法一樣。
你只是執行了5個計時3秒後運行的程式。
當然會在3秒後一口氣全放出來了。
一般正確的做法有兩種。
一種是 backcall 處理
如
test()
function test(){
setTimeout(() => {
console.log(n)
test();
}, 3000)
}
上面的寫法,就是會跑完3秒後,才再呼叫一次跑3秒。
另一種寫法則是+秒數。
var n=0;
var sec=3;
setTimeout(() => {
console.log(n)
n++
}, sec*1000)
sec+=3
setTimeout(() => {
console.log(n)
n++
}, sec*1000)
sec+=3
setTimeout(() => {
console.log(n)
n++
}, sec*1000)
以上給你參考