setTimeout迴圈:js非同步機制問題
阿新 • • 發佈:2020-12-19
技術標籤:javascript
最近寫前端時發現setTimeout和for迴圈相遇時,會發生一些特殊的情況,與預期的執行結果不符。
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
上述程式碼的執行結果為:6,6,6,6,6
這似乎與預期的1,2,3,4,5結果不符。
理想的執行步驟:
但是實際的執行步驟:
經過查閱資料,js存在同步和非同步的執行機制,同步事件的優先順序高於非同步事件。其中setTimeout是同步事件,會第一時間掛載到任務佇列,但是內部包含的回撥函式為非同步事件,必須等同步事件全部執行完畢才去執行。因此,示例指令碼的任務佇列為:
可以看出,出現與預期1,2,3,4,5結果不符的原因是
setTimeout中的回撥函式沒有與迴圈體同步執行,不能同步獲取 i 的取值,等迴圈體執行完畢的時候,i 的取值為6。
解決辦法:
將var替換為let。原理涉及到作用域問題,let為塊級作用域,會在整個塊級同步生效,包含非同步函式;var為函式級作用域,必須等同步函式執行完畢,才能賦值到下級非同步函式。