首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

JavaScript AJAX 巢狀迴圈陷阱:非同步閉包導致內層迴圈不執行

     編輯:程式設計綜合問答

現象重現

utils.Ajax(url, data, {showLoad:true}, function(data) {
    if (data.success) parseList(data.returnDTO.list);
});

function parseList(list) {
    utils.Ajax(url2, data2, {showLoad:true}, function(data) {
        if (data.success) {
            for (var j = 0; j < data.returnDTO.list.length; j++) {
                for (var i = 0; i < 5; i++) { /* 內層完全不進入 */ }
            }
        }
    });
}

外層 j 迴圈正常,內層 i 迴圈永遠不執行,alert 顯示兩次 AJAX 皆成功。

根本原因:變數遮蔽與非同步時序

  1. 變數提升:var i 在函式作用域被提升,若外層同名變數 i 存在,內層 var i 實際指向同一變數。
  2. 非同步回呼:外層 AJAX 回呼執行時,若先前同名 i 已被修改 (如為 5),內層判斷 i < 5 直接失敗。
  3. 資料長度為 0:data.returnDTO.list.length 可能為 0,導致外層迴圈零次,但提問者說外層能進入,故排除。

修正方案

✅ 方案一:使用 let 區塊作用域 (ES6+)

for (let j = 0; j < list.length; j++) {
    for (let i = 0; i < 5; i++) { /* 各迴圈擁有獨立 i, j */ }
}

✅ 方案二:立即叫用函式表達式 (IIFE) 封裝 (ES5)

for (var j = 0; j < list.length; j++) {
    (function(j) {
        for (var i = 0; i < 5; i++) { /* i 仍為 var,但 j 被鎖定 */ }
    })(j);
}

✅ 方案三:改用 forEach / map 函數式風格

list.forEach(item => {
    Array.from({length: 5}, (_, i) => { /* 安全 */ });
});

除錯技巧:優先檢查資料結構

如最佳回答建議,先在外層迴圈前 console.log(data.returnDTO.list.length) 確認資料筆數。若為 0,問題根本不在迴圈邏輯,而在上游 API 回傳空陣列。

最佳實務總結

  • 全專案啟用 "use strict" + ESLint no-var 規則,強制使用 let/const。
  • 非同步回呼中避免重用外層迴圈變數名稱。
  • 巢狀 AJAX 考慮改用 Promise.all / async-await 扁平化流程,減少回呼地獄。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved