2

我设置了通常的 XMLHttpRequest,到目前为止一切正常,我可以检索数据和 readyState 更改并执行各种操作。

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

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

我查看了XMLHttpRequest MDN 条目,但没有提到为什么当 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 以及在 Win 上使用 IE11 进行了检查,到处都是相同的行为,onreadystatechange() 永远不会为 readyState 0 触发。

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

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

更新

结果表明,在成功或失败的请求完成后,readyState 将永远保持在 4,并在 FF、IE、Safari 中进行了验证。

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

更新 3

根据XMLHttpRequest 规范,当 XHR 处于 readyState 3(接收)并被中止时,XHR 应该使用 onreadystatechange 事件将 readyState 设置为 4(完成),发出网络错误,然后在没有onreadystatechange 事件的情况下将 readyState 设置为 0(未发送) .

但是当我中止处于 readyState 3(接收)的 XHR 时,它首先会使用 onreadystatechange 事件和 HTTP 状态 200(OK)将 readyState 设置为 4(完成),然后它会触发 onabort 和 onloadend 并将 readyState 重置为 0( unsent) ...但绝不会触发 onerror 事件。

非常混乱。

4

3 回答 3

1

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

XHR 实例不可重用。如果Firefox 的 XHR 对象将状态从 4 带回 0 (它不适合我,见下文),那是 Firefox 特有的东西,但它没有用,而且它不会触发无用的事件也很好在上面。

状态从DONE(4) 变为UNSENT(0) 是没有意义的。请求并非未发送。完成了。

在评论中重新说明您的注释:

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

啊,好吧,那将是不同的——从3到 0,而不是从 4 到 0。如果我在 Chrome 和 Firefox 中做同样的事情,我也会看到这一点。

XHR 的规范abort说:

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

  2. 如果 aborted whenreadyState是 4,它应该变回 0——但是规范没有说它应该触发一个readystatechange事件(而它确实说其他时候状态会被各种算法改变)。

因此,在这种极端情况下,Chrome 和 Firefox 似乎都没有严格遵循规范。

于 2017-08-11T11:48:45.410 回答
0

默认性质

Readystate 0 属于未发送状态。这是创建 xhr 对象后的默认进入状态。此时事件处理程序'onreadystatechange'没有被调用,因为它被设计为只调用从0到某事的状态变化。

我收到了你的案子。现在我要回答你的问题**为什么当状态从 4 变为 0 时不会触发“onreadystatechange”?

     var xhr = new XMLHttpRequest();
 //here xhr.readystate is 0
 xhr.onreadystatechange = () => {
     console.log('state', xhr.readyState)
     //**session one** 
     // console will print 1 when request opened
     // 2 when sent and response header received
     // 3 when body is receiving 
     // 4 when done
     //**session two**
     // prints 1 
     //note:readystate comes to 1 directly from 4 not 0.The state 0 is 
     //only available upto very first time you called open
 }

 //session one
 xhr.open('GET', '/api', true);
 xhr.send()

 //session two
 //here xhr.readystate is 4
 xhr.open('GET', '/api', true);
 //here xhr.readystate is 1 there is no 0 in middle.
 xhr.send();
于 2017-08-11T12:41:27.703 回答
-1

0 是表示请求尚未发送的值。您无法取消发送请求,因此事件不会在从 4 变为 0 时触发。这就像您发送了一封邮件,然后等待您发送它。那没有意义。您只能等待其他事情发生(例如,邮递员拿走了它,它到达了......)但显然,如果您等待已经发生的事情,您将等待很长时间。

值 状态 描述

0 UNSENT 客户端已创建。open() 尚未调用。

1 OPENED open() 已被调用。

2 HEADERS_RECEIVED send() 已被调用,并且标头和状态可用。

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

4 DONE 操作完成。

更新

当我在寻找答案时,我发现了XMLHttpRequest的这个实现。这表明 abort 函数没有调度任何事件。这可能就是您无法捕获该事件的原因,因为它根本没有被触发。

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);
        * }
        */
    };
于 2017-08-11T11:51:42.320 回答