js实现ajax

120 阅读1分钟
var dftXHR = {
      url: null// 请求地址
      ,method: 'POST'// 请求类型
      ,data: {}// 传递数据
      ,async: true// 是否异步执行
      ,dataType:''//''默认值text
      ,header:{
          // 设置请求主体的数据类型
          'Content-Type':'application/x-www-form-urlencoded; charset=utf-8'
      }
      ,progress:function(){}
      ,before: function(){}// 请求发送前执行事件
      ,complete: function(){}// 请求发送后执行事件
      ,success: function(){}// 请求成功后执行事件
      ,fail: function(){}// 请求失败后执行事件
}

function isPlainObject(obj){
    if(!obj || typeof obj != 'object'){return false;}
    if(obj.constructor.prototype.hasOwnProperty("isPrototypeOf")){
        return true;
    }
    return false;
}

var sendxhr = function(options){
    let setting = Object.assign({},dftXHR,options)
    ,contentType = isPlainObject(setting.contentType) 
    ,xhr = new XMLHttpRequest()
    ,method = setting.method.toUpperCase()
    ,getQueryStr = method == 'GET' && /.+\?(.+)$/.exec(setting.url)[1] || ''
    ,setParams = function() {
        xhr.timeout = 25000;
        //设置想要的数据类型
        xhr.responseType = setting.dataType
        xhr.open(method,setting.url+getQueryStr,setting.async)
        // 此方法需要在open方法和send方法之间调用
        let header = setting.header
        for(let key in header){
            xhr.setRequestHeader(key,header[key]);
        }
        method == 'POST' && !'Content-Type' in header &&  xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=utf-8')
    }()
            
    ,evtListener = function(){
        xhr.addEventListener('loadstart', function(){ 
            setting.before(xhr);
        });
        //上传进度
        xhr.addEventListener('progress',function(e){
            //长度可计算并且readyState == '3'
            if(e.lengthComputable){
                setting.progress.call(xhr,e,e.loaded,e.total)
            }
        })
        // 监听onreadystatechange并执行成功失败事件
        // readyState可以用onload代替
        xhr.addEventListener('readystatechange',function(){
            if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300 || xhr.status==304)){
                setting.success.call(xhr,xhr.response,xhr.status)
            }else{
                setting.fail.call(xhr,xhr.status,xhr.statusText)
            }
        })
        //请求成功的事件
        // xhr.onload = function(){
        //     setting.complete.call(xhr, xhr.status);
        // };

        //无论请求成功还是失败都会执行的事件,
        xhr.addEventListener('loadend',function(){
            setting.complete.call(xhr,xhr.status,xhr.statusText)
        })
        //请求失败回调
        xhr.addEventListener('error',function(){ 
            setting.fail.call(xhr,xhr.status,xhr.statusText)
        })
        xhr.addEventListener('timeout',function(){
            setting.fail.call(xhr,xhr.status,xhr.statusText)
            xhr.abort();
        })
    }()

    ,assembleQueryStr = function(obj){ 
        let args = "";
        Object.keys(obj).forEach(function(key){
            let val = obj[key]||''
            args += key+"="+decodeURIComponent(val)+"&";
        });
        return args.substring(0,args.length-1);
    }

    xhr.send(assembleQueryStr(setting.data));
}