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

JavaScript AJAX 回調中正確使用 XMLHttpRequest 對象:閉包與全局變量陷阱

     編輯:程式設計綜合問答

錯誤代碼

window.onload = function() {
    var xmlHttp = createXMLHttpRequest();
    xmlHttp.open("GET", "/ajax/PServlet", true);
    xmlHttp.send(null);
    xmlHttp.onreadystatechange = load(xmlHttp); // 錯誤:立即執行 load,返回值 (undefined) 賦給處理器
};

function load(xmlHttp) {
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { ... }
}

三大錯誤

  1. 賦值處理器時調用了函數: load(xmlHttp) 會**立即執行** load,返回 undefined 賦給 onreadystatechange。正確是賦值**函數引用**:load。
  2. 局部變量 xmlHttp 在回調時可能已變/丟失: 雖然閉包能捕獲,但異步回調時外層函數已結束,若複用變量發起多請求會串聯。
  3. 未處理 readyState 變化流程: 必須在回調內判斷 readyState === 4。

修正方案一:全局/外部變量 + 函數引用 (傳統修法)

var xmlHttp; // 全局/模塊級

window.onload = function() {
    xmlHttp = createXMLHttpRequest();
    xmlHttp.open("GET", "/ajax/PServlet", true);
    xmlHttp.send(null);
    xmlHttp.onreadystatechange = load; // 僅函數名
};

function load() {
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
        // 處理 xmlHttp.responseText
    }
}

修正方案二:閉包捕獲單個請求對象 (推薦,支持並發)

window.onload = function() {
    var xhr = createXMLHttpRequest(); // 局部常量
    xhr.open("GET", "/ajax/PServlet", true);
    xhr.send(null);
    xhr.onreadystatechange = function() { // 箭頭函數/匿名函數形成閉包
        if (xhr.readyState == 4 && xhr.status == 200) {
            // 直接使用 xhr
            console.log(xhr.responseText);
        }
    };
};

現代最佳實踐:Fetch API / Axios (拋棄原生 XHR)

// Fetch + async/await
async function fetchData() {
    try {
        const response = await fetch('/ajax/PServlet');
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const data = await response.text(); // 或 json()
        console.log(data);
    } catch (err) {
        console.error(err);
    }
}

// Axios (需引入庫)
axios.get('/ajax/PServlet')
    .then(res => console.log(res.data))
    .catch(err => console.error(err));

關鍵點總結

錯誤寫法正確寫法原因
onreadystatechange = load(xhr)onreadystatechange = load 或 = () => { ... }賦值函數引用而非調用結果
全局 var xhr 共用請求內部 const xhr + 閉包避免併發請求覆蓋/競態
同步 open(..., false)異步 open(..., true) + 回調/Promise不阻塞主線程,體驗好
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved