onload เท่ากับ readyState == 4 ใน XMLHttpRequest หรือไม่


122

ฉันสับสนเกี่ยวกับเหตุการณ์ผลตอบแทน xhr อย่างที่ฉันบอกได้ว่าonreadystatechange -> readyState == 4และ onload ไม่แตกต่างกันมากนักมันเป็นความจริงหรือไม่

var xhr = new XMLHttpRequest();
xhr.open("Get", url, false);
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4)
    {
        /* do some thing*/
    }
};

xhr.send(null);

หรือ

xhr.onload = function() { /* do something */ }

13
หากใครมองว่านี่เป็นตัวอย่างโปรดสังเกตว่ามันใช้ async = false (อาร์กิวเมนต์ที่ 3 ของ xhr.open) ซึ่งปกติแล้วไม่ใช่สิ่งที่คุณต้องการ
eddiewould

คำตอบ:


66

มันควรจะเป็นเรื่องเดียวกัน onloadถูกเพิ่มใน XMLHttpRequest 2 ในขณะที่onreadystatechangeมีมาตั้งแต่สเป็คดั้งเดิม


ดูเหมือนว่า Safari บนมือถือจะไม่กลับมาเมื่อใช้งาน onload onreadystatechange ใช้งานได้แม้ว่า
Kai Hartmann

1
ไม่มีการแบ่งแยกที่ชัดเจนอย่างแท้จริงระหว่าง XHR 1 และ XHR 2 อีกต่อไปพวกเขาได้รวมเป็นมาตรฐานเดียว คุณลักษณะทั่วไปที่แสดงถึง XHR 2 คือการรองรับ CORS ดังนั้นจากจุดยืนดังกล่าว XHR 2 จึงไม่ปรากฏใน IE จนกระทั่ง IE 10 แต่ XHR.onload ได้รับการสนับสนุนใน IE 9 ซึ่งโดยทั่วไปเชื่อว่าเป็น XHR 1
Chase

153

นี่เป็นความจริงเกือบตลอดเวลา อย่างไรก็ตามความแตกต่างที่สำคัญอย่างหนึ่งคือonreadystatechangeตัวจัดการเหตุการณ์จะถูกทริกเกอร์ด้วยreadyState==4ในกรณีที่onerrorตัวจัดการมักจะถูกทริกเกอร์ (โดยทั่วไปจะเป็นปัญหาการเชื่อมต่อเครือข่าย) ได้รับสถานะเป็น 0 ในกรณีนี้ ฉันได้ตรวจสอบแล้วว่าสิ่งนี้เกิดขึ้นกับ Chrome, Firefox และ IE ล่าสุด

ดังนั้นหากคุณกำลังใช้onerrorและกำหนดเป้าหมายเบราว์เซอร์สมัยใหม่คุณไม่ควรใช้onreadystatechangeแต่ควรใช้onloadแทนซึ่งดูเหมือนว่าจะรับประกันได้ว่าจะถูกเรียกเมื่อคำขอ HTTP เสร็จสมบูรณ์เท่านั้น (ด้วยการตอบกลับจริงและรหัสสถานะ) มิฉะนั้นคุณอาจได้รับตัวจัดการเหตุการณ์สองตัวที่ทริกเกอร์ในกรณีที่เกิดข้อผิดพลาด (ซึ่งเป็นวิธีที่ฉันพบในเชิงประจักษ์เกี่ยวกับกรณีพิเศษนี้)

นี่คือลิงค์ไปยังโปรแกรมทดสอบ Plunker ที่ฉันเขียนไว้ซึ่งให้คุณทดสอบ URL ที่แตกต่างกันและดูลำดับเหตุการณ์และreadyStateค่าที่แท้จริงตามที่แอป JavaScript เห็นในกรณีต่างๆ โค้ด JS ยังแสดงอยู่ด้านล่าง:

var xhr;
function test(url) {
    xhr = new XMLHttpRequest();
    xhr.addEventListener("readystatechange", function() { log(xhr, "readystatechange") });
    xhr.addEventListener("loadstart", function(ev) { log(xhr, "loadstart", ev.loaded + " of " + ev.total) });
    xhr.addEventListener("progress", function(ev) { log(xhr, "progress", ev.loaded + " of " + ev.total) });
    xhr.addEventListener("abort", function() { log(xhr, "abort") });
    xhr.addEventListener("error", function() { log(xhr, "error") });
    xhr.addEventListener("load", function() { log(xhr, "load") });
    xhr.addEventListener("timeout", function(ev) { log(xhr, "timeout", ev.loaded + " of " + ev.total) });
    xhr.addEventListener("loadend", function(ev) { log(xhr, "loadend", ev.loaded + " of " + ev.total) });
    xhr.open("GET", url);
    xhr.send();
}

function clearLog() {
    document.getElementById('log').innerHTML = '';
}

function logText(msg) {
    document.getElementById('log').innerHTML += msg + "<br/>";
}

function log(xhr, evType, info) {
    var evInfo = evType;
    if (info)
        evInfo += " - " + info ;
    evInfo += " - readyState: " + xhr.readyState + ", status: " + xhr.status;
    logText(evInfo);
}

function selected(radio) {
    document.getElementById('url').value = radio.value;
}

function testUrl() {
    clearLog();
    var url = document.getElementById('url').value;
    if (!url)
        logText("Please select or type a URL");
    else {
        logText("++ Testing URL: " + url);
        test(url);
    }
}

function abort() {
    xhr.abort();
}

2
@Fernando ชี้แจงภายในonload, readyState === 4รับประกันได้ว่าจะได้รับสิทธิจริงหรือไม่?
kgf3JfUtW

6
@sam ใช่ดูเหมือนว่าจะเป็นเช่นนั้นเสมอไปแม้ว่าสิ่งที่ตรงกันข้ามจะไม่เป็นความจริงอย่างชัดเจนก็ตามreadyStateอาจเป็น 4 ในerrorหรือabortกรณีเช่นกัน สถานะนี้โดยทั่วไปหมายถึงกระบวนการโหลดเสร็จสิ้นไม่ว่าจะสำเร็จหรือไม่ก็ตาม สำหรับปกติโหลดประสบความสำเร็จในลำดับสุดท้ายของเหตุการณ์: progress(ที่มีข้อมูลทั้งหมดที่โหลด) readystatechange(กับ)readyState == 4 , loadloadend
Fernando Echeverria

2
โปรดทราบว่าonloadจะไม่เกิดขึ้นหากNo 'Access-Control-Allow-Origin' header is present on the requested resource.
deathangel908

นั่นคือเรื่องจริง นั่นเป็นหนึ่งในกรณีที่ทริกเกอร์onerrorตัวจัดการ
Fernando Echeverria

1
@Pacerier: ใช่โปรดดูที่นี่: การทดสอบ plnkr
Fernando Echeverria

11

ไม่พวกเขาไม่เหมือนกัน หากคุณพบข้อผิดพลาดของเครือข่ายหรือยกเลิกการดำเนินการonloadจะไม่ถูกเรียก จริงๆแล้วเหตุการณ์ที่ใกล้เคียงที่สุดreadyState === 4ก็loadendคือ โฟลว์มีลักษณะดังนี้:

     onreadystatechange
      readyState === 4
             
 onload / onerror / onabort
             
         onloadend
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.