关于 js ajax readyState 的阐述

发布时间 2023-10-19 12:39:44作者: 万物有序

为了弄清楚 ajax readyState 的具体意义,做了如下测试:

index.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3   <head>
 4     <meta charset="UTF-8" />
 5     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 6     <title>Document</title>
 7   </head>
 8   <body>
 9     <script>
10       const xhr = new XMLHttpRequest();
11 
12       console.log(xhr.readyState);
13 
14       xhr.open("POST", "http://localhost/a.json", true);
15 
16       console.log(xhr.readyState);
17 
18       xhr.onreadystatechange = function () {
19         if (xhr.readyState === 2) {
20           console.log(
21             2,
22             xhr.getAllResponseHeaders(),
23             xhr.responseText.slice(-10)
24           );
25         }
26         if (xhr.readyState === 3) {
27           console.log(3, xhr.responseText.slice(-10));
28         }
29         if (xhr.readyState === 4 && xhr.status === 200) {
30           console.log(4, xhr.responseText.slice(-10));
31         }
32       };
33       xhr.onerror = function (err) {
34         reject(err);
35       };
36       // 这里会触发预检请求,需要服务端做相关配置
37       // 或者使用 text/plain
38       xhr.setRequestHeader("Content-Type", "application/json");
39 
40       xhr.send(JSON.stringify({ step: 0 }));
41     </script>
42   </body>
43 </html>

server.js

 1 const http = require("http"); // node内部模块,用来创建http服务器
 2 
 3 const server = new http.Server();
 4 
 5 server.on("request", (req, res) => {
 6   res.writeHead(200, {
 7     "Content-Type": "text/plain",
 8     "Access-Control-Allow-Origin": "*",
 9     // 预检请求可以接受的请求头
10     "Access-Control-Allow-Headers": "Content-Type",
11     // 设置自定义响应头并暴露给浏览器 js
12     "define-none": "none",
13     "Access-Control-Expose-Headers": "define-none",
14   });
15 
16   req.on("data", (data) => data);
17 
18   req.on("end", () => {
19     // 预检请求不发送响应体
20     if (req.method === "OPTIONS") {
21       res.end();
22       return false;
23     }
24     res.write(
25       JSON.stringify(Array.from({ length: 10 ** 5 }).map((val, index) => index))
26     );
27     res.end();
28   });
29 });
30 
31 server.listen(80);

打印结果:

结论:xhr 初始化以后读取状态是 0;open 建立请求以后读取状态变更为 1,接下来的状态变更就可以用 onreadystatechange 监听了;send 发送请求以后等待服务端响应,接收到响应报文以后读取状态变更为 2,此时 js 可以拿到响应头,但是响应体是空字符串,说明浏览器没有拿到响应体或者没有完成响应体的解析;接下来读取状态变更为 3,在打印结果中可以看到 js 已经拿到了一小段响应体数据,当然如果传输数据量小的话也可以拿到完整的响应体;接下来读取状态变更为 4 的时候,js 可以拿到完整的响应体,所以通常我们在 readyState === 4 的时候对数据进行处理。

 

const http = require("http"); // node内部模块,用来创建http服务器

const server = new http.Server();

server.on("request", (req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain",
    "Access-Control-Allow-Origin": "*",
    // 预检请求可以接受的请求头
    "Access-Control-Allow-Headers": "Content-Type",
    // 设置自定义响应头并暴露给浏览器 js
    "define-none": "none",
    "Access-Control-Expose-Headers": "define-none",
  });

  req.on("data", (data) => data);

  req.on("end", () => {
    // 预检请求不发送响应体
    if (req.method === "OPTIONS") {
      res.end();
      return false;
    }
    res.write(
      JSON.stringify(Array.from({ length: 10 ** 5 }).map((val, index) => index))
    );
    res.end();
  });
});

server.listen(80);