XMLHttpRequest onreadystatechange从未为readyState 0

时间:2017-08-11 11:46:25

标签: javascript ajax xmlhttprequest readystate onreadystatechange

我设置了通常的XMLHttpRequest,到目前为止一切正常,我可以检索数据和readyState更改,并做各种各样的事情。

但有一件事情是,readyState会在到达0时触发onreadystatechange()函数。

现在我想知道......为什么?

我查看了XMLHttpRequest MDN entry但是没有提到为什么当readyState达到0时onreadystatechange不应该触发。我也没有找到关于该主题的其他信息......

段:

// Inside a class, this = class instance
this.socket = new XMLHttpRequest();

// For easy access of this class instance in onreadystatechange
var client = this;

// Write current readyState to console
this.socket.onreadystatechange = function ()
{
    // Adding this just to verify there are no errors in if block
    console.log("readyState: "+client.socket.readyState);

    if(client.socket.readyState === 0)
    {
        console.log("readyState is 0");
    }
    else
    {
        console.log("readyState is "+client.socket.readyState);
    }
}

当XMLHttpRequest套接字完成处理请求时,XMLHttpRequest实例将具有值readyState === 0,至少Firefox的JS控制台告诉我。

在执行请求后,JS控制台正确列出了readyStates 1-4的日志消息,但没有为readyState 0发送消息,而不是在请求之前,而不是之后。

理论上,当readyState从4变回0时,不应该触发onreadystatechange()函数吗?在macOS上使用当前的FF和Safari以及在使用IE11的Win上检查这一点,到处都是相同的行为,onreadystatechange()永远不会为readyState 0触发。

XMLHttpRequest是故意不按设计做的,还是我做错了什么?感谢任何有用的输入。 :)

(请不要“使用jQuery”评论或类似,thx。)

更新

在成功或失败的请求完成后,在FF,IE,Safari中验证,readyState将永久保留为4。

但是,readyState将从>返回如果正在进行的请求被中止,则为0到0。所以一个readystatechange确实发生了,但onreadystatechange没有被触发,在FF和Safari中验证了这一点。

更新3

根据XMLHttpRequest spec,当XHR处于readyState 3(接收)并中止时,XHR应使用onreadystatechange事件将readyState设置为4(完成),发出网络错误,然后将readyState设置为0(不带 onreadystatechange事件。

但是当我中止处于readyState 3(接收)的XHR时,它将首先使用onreadystatechange事件和HTTP状态200(OK)将readyState设置为4(完成),然后它将触发onabort和onloadend并重置readyState到0(未发送)......但是在任何时候都没有触发onerror事件。

非常混乱。

2 个答案:

答案 0 :(得分:1)

  

理论上,当readyState从4变回0时,不应该触发onreadystatechange()函数吗?

XHR实例不可重用。 如果 Firefox的XHR对象将状态从4恢复为0 (它不适合我,请参见下文),这是Firefox特有的,但它没用,并且它也不会在它上面发出无用的事件。

状态从DONE(4)转到UNSENT(0)是没有意义的。请求未发送。它已经完成了

在评论中重新注明:

  

但是在中止之后,它返回0 ---它已经处于readyState 3并且检索文件...

啊,好吧,那会有所不同 - 从 3 到0,而不是从4到0.我也看到了,如果我在Chrome和Firefox中都这样做的话。

The spec for XHR's abort说:

  1. 当您说(readyState 3)时中止,readyState应该更改回0;相反,它应该更改为4,将响应设置为网络错误,并触发readystatechange事件。

  2. 如果在readyState为4时中止,它应该更改回0 - 但规范说它应该触发readystatechange事件(而它确实说其他时候状态是由各种算法改变的。)

  3. 因此,似乎Chrome和Firefox都没有严格遵循此边缘情况下的规范。

答案 1 :(得分:-1)

0表示尚未发送请求的值。您无法发送请求,因此无法将事件从4更改为0。 就像你发了一封邮件然后等你发送邮件一样。这毫无意义。你只能等待其他事情发生(例如邮递员接受它,它到达,......)但很明显,如果你等待已经发生的事情,你将等待很长时间。

  

值状态描述

     

0已创建UNSENT客户端。 open()还没有被调用。

     

已打开1个已打开的open()。

     

已调用HEADERS_RECEIVED发送(),标题和状态为   可用。

     

3加载下载; responseText保存部分数据。

     

4 DONE操作完成。

<强>更新

在我寻找答案的过程中,我发现了XMLHttpRequest的这种实现方式。这表明中止功能不会发送任何事件。这可能是你无法抓住这个事件的原因,因为它根本就没有被解雇。

cXMLHttpRequest.prototype.abort = function() {
        // Add method sniffer
        if (cXMLHttpRequest.onabort) {
            cXMLHttpRequest.onabort.apply(this, arguments);
        }

        // BUGFIX: Gecko - unnecessary DONE when aborting
        if (this.readyState > cXMLHttpRequest.UNSENT) {
            this._aborted = true;
        }

        this._object.abort();

        // BUGFIX: IE - memory leak
        fCleanTransport(this);

        this.readyState = cXMLHttpRequest.UNSENT;

        delete this._data;

        /* if (this._async) {
        *   fQueue_remove(this);
        * }
        */
    };