使用XMLHttpRequest实现AJAX

通过 XMLHttpRequest, ActiveXObject 实现 ajax

Featured image

通过 XMLHttpRequest, ActiveXObject 实现 ajax 请求

因项目是Web App,在接手项目时就已使用fetch,而 ipad 下并不支持 fetch。所以,在做网络请求部分做了点处理

XMLHTttpRequestfetch是浏览器的原生API,而ajax的核心是 XMLHTttpRequest对象

创建XHR

const XHR = {
    createActiveXObject: function() {
        try{
            return new window.ActiveXObject("Microsoft.XMLHttp");
        }catch(e){}
    },
    createStandardXHR: function(){
        try{
            return new window.XMLHttpRequest();
        }catch(e){}
    },
    getXHR: function(){
        var XHR = null;
        if(typeof window.ActiveXObject != 'undefined'){
            XHR = xhr.createActiveXObject();
        }else{
            XHR = xhr.createStandardXHR();
        }
        return XHR;
    },
    onreadystatechange: function(xhr, callback){
        if(!callback){return;}
        if(xhr.readyState == 4){
            if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                callback(xhr.responseText);
            }
        }
    },
    ontimeout: function(callback){
        if(!callback){return;}
        callback();
    },
    onprogress: function(event,callback){
        if(!callback){return;}
        callback(event);
    }
}

使用XHR

let xhr = XHR.getXHR();
xhr.onreadystatechange = XHR.onreadystatechange(function(data){
    console.log(data);
});

xhr.timeout=10000;

xhr.ontimeout = XHR.ontimeout(function(){
    alert("timeout");
});

xhr.onprogress = XHR.onprogress(function(event){
    console.log(event.totalSize);
});

xhr.open("get","url",true);
xhr.send(null);

大体的流程

初始化请求

使用XHR对象时,使用的第一个方法就是open(),这个方法不会发送请求,但会初始化一个请求准备发送

open方法接收三个参数: 规定请求类型(POST或GET)、请求地址url、异步(true)同步(false)

xhr.open('get', 'example.php', false);

发送请求

GETPOST两种。GET 请求方式是通过URL参数将数据提交到服务器的,POST 则是通过将数据作为send的参数提交到服务器

GET请求:发送的值为空,一般写上null

xhr.open('GET', url);
xhr.send(null);

POST请求,要设置表单提交的内容类型。要模拟表单提交请求的话就将Content-type头部信息设置为application/x-www-form-urlencoded,并将发送的参数经过encodeURIComponent()方法进行编码。

定义请求的头部信息,在send()与open()方法之间进行设置; setRequestHeader(header,value) 向请求添加请求头,header:规定头的名称,value:规定头的值

参数列表以“key=value”的形式,key和value都需要进行编码,因为包含特殊字符。每次请求的时候都会在参数列表中拼入一个“v=xx”的随机字符串,这样是为了拒绝缓存,每次都直接请求到服务器上

XHR.send(null) :发送请求,当没有参数传递时,参数为null;当为get请求时,携带的参数需要通过encodeURIComponent进行编码

xhr.open('POST', url);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(stringData);

监控请求状态,处理请求数据

xhr对象有且仅有一个事件onreadystatechange,每一次xhr对象的 readyState状态值改变都会触发该事件,但是该方法不能为单独的一个xhr对象绑定多个事件处理逻辑,即 onreadystatechange 只能绑定一个事件处理的function,如果你想处理多件事情,那么只能在绑定的function中进行多事件处理的逻辑调用

当为异步请求时,XHR的readystate属性表示请求/响应过程的当前活动阶段

0-未初始化,尚未调用open()方法;
1-启动,调用了open()方法,未调用send()方法; 服务器连接已建立;
2-发送,已经调用了send()方法,未接收到响应; 请求已接收;
3-接收,已经接收到部分响应数据; 请求处理中;
4-完成,已经接收到全部响应数据; 请求已完成;

xhr对象有且仅有一个事件onreadystatechange,每一次xhr对象的 readyState状态值改变都会触发该事件,因此要在调用open()之前指定onreadystatechange事件以便判断是否已经响应完成且可以使用数据了;该方法不能为单独的一个xhr对象绑定多个事件处理逻辑,即 onreadystatechange 只能绑定一个事件处理的function,如果你想处理多件事情,那么只能在绑定的function中进行多事件处理的逻辑调用

readystatechange事件中,先判断响应是否接收完成,然后判断服务器是否成功处理请求,xhr.status 是状态码,状态码以2开头的都是成功,304表示从缓存中获取

接收到响应后,响应的数据会自动填充XHR对象,相关属性有:

responseText:获得字符串形式的响应数据
responseXML:获得XML形式的响应数据
status:响应的HTTP状态码
statusText:HTTP状态的说明
xhr.onreadystatechange = function(){
  if(xhr.readyState == 4){
      if(xhr.status == 200){
          document.getElementById("unInfo").innerHTML = xhr.responseText;
      }
  }
}

创建 ajax 函数

function ajax(options){
    options = options||{};
    optoins.type = (options.type||'GET').toUpperCase();
    options.dataType = options.dataType||'json';
    params = formatParams(options.data);

    // 创建
    let xhr = XHR.getXHR()
    xhr.timeout=10000

    //提交数据
    if(options.type === 'GET') {
        xhr.open('GET',options.url+'?' + params, true)
        xhr.send(null)
    }else if(options.type === 'POST') {
        xhr.open('POST',options.url,true);
        //设置表单提交时的内容类型
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.send(params);
    }

    // 接收
    xhr.onreadystatechange = function(){
        if(xhr.readyState==4){
            var status=xhr.status;
            if(status>=200 && status < 300 || xhr.status == 304){
                options.success && options.success(xhr.responseText,xhr.responseXML);
            }else{
                options.error && options.error(status);
            }
        }
    }
}

function formatParams(data){
    var arr=[];
    for(var name in data){
        arr.push(encodeURIComponent(name)+'='+encodeURIComponent(data[name]));
    }
    arr.push(('v='Math.random()).replace('.',''));
    return arr.join('&');
}

ajax({
    url:'http://localhost:8080/test.php',
    type:'POST',
    dataType:'json',
    data:{name:'John', age:18},
    success:function(response,xml){
        //请求成功后执行的代码
    },
    error:function(status){
        //失败后执行的代码
    }
})

参考