Ajax里的XHR对象支持单例模式吗

315 阅读1分钟

之前跟同事探讨一个Ajax的问题:ajax是否可以封装一下,实现其他类库如Axios的单例模式呢?对当时的结论不置可否,今天验证一下

服务端代码准备

通过express写一些基础代码:

const express = require('express');
const path = require('path')
const app = express();
// 提供一个接口
app.get("/api/greeting",(req,res,next)=>{
    console.log('收到请求!');
    res.send("Nice to see you!");
})
//监听3000端口
app.listen(3000,()=>{
  console.log('server on 3000!');
})

客户端代码

客户端并发两个请求

var xhr = new XMLHttpRequest();
xhr.onload = function(event){
  console.log(event.target.responseText)
}
function sendRequest(){
  xhr.open("get","/api/greeting");
  xhr.send();
}
//第一个请求
sendRequest()
//第二个请求
sendRequest();

服务端打印显示两次请求均已收到:

image.png

客户端网络控制台显示第一个请求被取消了(其实发出去了,但是浏览器将其丢弃了):

XHR实例串行请求

var xhr = new XMLHttpRequest();
function sendRequest() {
  return new Promise((res, rej) => {
    xhr.onload = function (event) {
      res(event.target.responseText);
    };
    xhr.open("get", "/api/greeting");
    xhr.send();
  });
}
//请求一
sendRequest().then(data=>{
  console.log(data)
  //请求二
  return sendRequest()
}).then(data=>{
  console.log(data)
})

结论

总结一下就是:xhr支持单例模式,使用一个实例负责所有请求,但是只能串行,并行会自动忽略前面未拿到响应的请求。

可以通过工厂函数实时创建新XHR实例,单个实例负责一次请求,用完丢弃。

例如jQuery里的做法:

image.png

每次send请求时都会调用工厂方法xhr(),xhr方法实时生成一个XMLHttpRequest实例