原生ajax的封装之旅

(ps:一直使用的时jquery封装好的ajax,没有对此深究过,直到看到了一些面试题,才发现对此一无所知。)

参考文档:https://segmentfault.com/a/1190000004322487

简单使用:

//get
    var ajax = new XMLHttpRequest();
    ajax.open('get','./1.php?name=233');
    ajax.send();
    ajax.onreadystatechange = function(){
        if(ajax.readyState == 4 && ajax.status == 200){
            console.log(ajax.responseText);
        }
    }

    // post
    var xhr = new XMLHttpRequest();
    xhr.open('post', '1.php' );
    xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xhr.send('name=fox&age=18');
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
      } 
    };

简单封装:

function ajax(opt){
        opt = opt || {};
        opt.method = opt.method.toUpperCase() || 'POST';
        opt.url = opt.url || '';
        opt.async = opt.async || true;
        opt.data = opt.data || null;
        opt.success = opt.success || function(){};

        var xmlHttp = null;
        if (XMLHttpRequest) {
             xmlHttp = new XMLHttpRequest();
        } else {
             xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
        }
        var params = [];

        for(var key in opt.data){ params.push(key+"="+opt.data[key]); }

        var postData = params.join("&");

        if(opt.method === 'POST'){
            xmlHttp.open(opt.method,opt.url,opt.async);
            xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
            xmlHttp.send(postData);
        } else {
            xmlHttp.open(opt.method,opt.url+'?'+postData,opt.async);
            xmlHttp.send(null);
        }
        xmlHttp.onreadystatechange = function(){
            if(xmlHttp.readyState == 4 && xmlHttp.status === 200){
                opt.success(xmlHttp.responseText);
            }
        }
    }
  // 使用
  ajax({
    method: 'post',
    url: './1.php',
    data: {
        name: "prayer",
        age: 15
    },
    success: function(response){
        console.log(response);
    }
  });  

1.php代码

<?php
/**
 * @Author: anchen
 * @Date:   2018-07-20 17:38:33
 * @Last Modified by:   anchen
 * @Last Modified time: 2018-07-20 18:01:07
 */
if(isset($_GET['name'])){
    echo 'hello '.$_GET['name'];
} else if ($_POST['name']&&$_POST['age']) {
    echo 'hello '.$_POST['name'].' you are '.$_POST['age'];
} else {
    echo 'nobody';
}

如果你想要更详细的兼容,可以参考

function createXHR(){
        if(typeof XMLHttpRequest != "undefined"){
            createXHR = function(){
                return new XMLHttpRequest();
            }
        } else if (typeof ActiveXObject != "undefined"){
            createXHR = function(){
                if(typeof arguments.callee.activeXString != "string"){
                    var verions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],
                        i,len;
                    for(i=0,len=verions.length;i<len;i++){
                        try{
                            new ActiveXObject(verions[i]);
                            arguments.callee.activeXString = verions[i];
                            break;
                        } catch(ex){

                        }
                    }
                }
                return new ActiveXObject(arguments.callee.activeXString);
            };
        } else {
            createXHR = function(){
                throw new Error("No XHR object available");
            }
        }
    }

promise封装

/**
     *   ajax函数,返回一个promise对象
     *   @param{object} opt 参数设置,支持的参数如下
     *      url:               url地址,默认空
     *      method:            请求方法,默认GET
     *      async:             是否异步,默认true
     *      data:              发送的数据,默认为空
     *      dataType:          接收的数据的类型,默认text
     *      iscors:            是否跨域携带cookie信息
     *   @return{promise}
     *       该函数注册xmlHttp.onloadend回调函数,判断xmlHttp.status是否属于 [200,300)&&304 
     *       如果属于则promise引发resolve状态,允许拿到xmlHttp对象
     *       如果不属于,或已经引发了ontimeout,onabort,则引发reject状态,允许拿到xmlHttp对象
     *   @reject
     *       返回一个对象,包含
     *       errorType: 错误类型
     *           abort_error:   xmlHttp对象调用abort函数
     *           timeout_error: 请求超时
     *           onerror:       xmlHttp对象出发了onerror事件
     *           send_error:    发送请求出现错误
     *           status_error:  响应状态不属于(200,300)&&304
     */
    function ajax(opt){
        //设置参数默认值
        opt = opt || {};
        opt.url = opt.url || '';
        opt.method = opt.method.toUpperCase() || 'POST';
        opt.async = opt.async || true;
        opt.data = opt.data || null;
        opt.timeout = opt.timeout || 0;
        opt.dataType = opt.dataType || 'text';
        opt.iscors = opt.iscors || false; 
        //设置钩子函数默认值
        
        //处理data参数
        if(opt.data !== null){
            var params = [];
            for(var key in opt.data){ params.push(key+"="+opt.data[key]); }
            opt.data = params.join("&");
        }
        //新建xmlHttp对象
        var xmlHttp = null;
        if (XMLHttpRequest) {
             xmlHttp = new XMLHttpRequest();
        } else {
             xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
        }
        //返回一个Promise对象
        return new Promise(function(resolve,reject){
            if(opt.method === 'POST'){
                xmlHttp.open(opt.method,opt.url,opt.async);
                xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
            } else {
                xmlHttp.open(opt.method,opt.url+'?'+opt.data,opt.async);
            }
            xmlHttp.timeout = opt.timeout;//设置超时
            xmlHttp.responseType = opt.dataType;//设置接受的数据类型
            
            //追踪Ajsx请求的当前状态,钩子函数
            xmlHttp.onreadystatechange = function(){
                switch(xmlHttp.readyState){
                    case 0: //UNSET     
                        console.group("xmlHttp对象成功构造");
                            console.log(xmlHttp);
                        console.groupEnd();
                        break;
                    case 1: //OPENED
                        console.group("open()方法已被调用");
                                console.log(xmlHttp);
                        console.groupEnd();
                        break;
                    case 2: //HEADERS_RECEIVED
                        console.group("响应头和响应状态已经返回");
                                console.log(xmlHttp);
                        console.groupEnd();
                        break;
                    case 3: //LOADING
                        console.group("响应体正在被下载,responce可能有数据了");
                                console.log(xmlHttp);
                        console.groupEnd();
                        break;
                    case 4: //DONE
                        console.group("数据传输结束,无论成败");
                                console.log(xmlHttp);
                        console.groupEnd();
                        break;
                }
            }

            xmlHttp.onloadstart = function(){
                console.group("xmlHttp触发send()");
                    console.log(xmlHttp);
                console.groupEnd();
            };
            xmlHttp.onprogress = function(){
                console.group("xmlHttp下载阶段,readystate=3时,50ms触发一次");
                    console.log(xmlHttp);
                console.groupEnd();
            };
            xmlHttp.upload.onprogress = function(){
                console.group("xmlHttp触发send()后,readystate=2之前的上传阶段,50ms触发一次");
                    console.log(xmlHttp);
                console.groupEnd();
            };
            //成功事件
            xmlHttp.onload = function(){
                if(xmlHttp.status >=200 && xmlHttp.status < 300 || xmlHttp.status == 304){
                    resolve(xmlHttp);
                } else {
                    //resolve other status,like 404
                    reject({
                        errorType: 'status_error',
                        xmlHttp: xmlHttp
                    })
                }
            };
            xmlHttp.onloadend = function(){
                console.group("请求结束,无论成败");
                    console.log(xmlHttp);
                console.groupEnd();
            };
            xmlHttp.onabort = function(){
                reject(new Error({
                    errorType: 'abort_error',
                    xmlHttp: xmlHttp
                }));
            };
            xmlHttp.ontimeout = function(){
                reject({
                    errorType: 'timeout_error',
                    xmlHttp: xmlHttp
                });
            };
            xmlHttp.onerror = function(){
                reject({
                    errorType: 'onerror',
                    xmlHttp: xmlHttp
                })
            };
            
            //处理网络错误
            try {
                xmlHttp.send(opt.data);
            } catch(e){
                reject({
                    errorType: 'send_error',
                    error: e
                });
            }
        });
    }
    //使用示例
    ajax({
        method: 'post',
        url: './1.php',
        data: {
            name: "prayer",
            age: 15
        },
        timeout: 200
    }).then(function(xmlHttp){
        //do something witch success
        console.log('成功获取数据: ',xmlHttp.response);
    }).catch(function(e){
        //do something witch error
        console.error('error: ',e);
    })

来看看整个过程发生了那些事情

如果有什么不明白的地方,可以私信我>.<

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值