美文网首页前端开发那些事儿
一篇搞清AJAX及实现手动封装

一篇搞清AJAX及实现手动封装

作者: 深度剖析JavaScript | 来源:发表于2020-09-07 12:04 被阅读0次

所谓AJAX就是异步JavaScriptXML,是一种无须加载整个网页就能实现更新部分网页的技术

那如何发送一个AJAX请求

1. 创建一个异步对象
var xmlhttp; 
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari 
  xmlhttp=new XMLHttpRequest(); 
}else {// code for IE6, IE5 
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
}

通过XMLHttpRequest构造函数创建一个异步对象xmlhttp, IE6, IE5 使用ActiveXObject创建,创建的这个异步对象上有很多属性和方法,常用的有:
(1)onreadystatechange
监听异步对象请求状态码readyState的改变,每当readyState改变时,就会触发onreadystatechange事件
(2)readyState:请求状态码
readyState表示异步对象目前的状态,状态码从0到4:
0: 表示请求未初始化,还没有调用open()
1: 服务器连接已建立,但是还没有调用 send()
2: 请求已接收,正在处理中(通常现在可以从响应中获取内容头)
3: 请求处理中,通常响应中已有部分数据可用了,没有全部完成
4: 当readyState状态码为4时,表示请求已完成;此阶段确认全部数据都已经解析完毕,可以通过异步对象的属性获取对应数据
(3)status:http状态码
http状态码表示成功的http状态码有xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status == 304
(4)responseText:后台返回的字符串形式的响应数据
(5)responseXML:后台返回的XML形式的响应数据

2. 设置请求方式和请求地址

创建异步对象之后,通过open()方法设置ajax请求方式和请求地址
格式:xmlhttp.open("GET/POST","ajax-get.txt",true);
第一个参数:请求的类型;GET还是POST
第二个参数:表示请求的文件的地址url
第三个参数:设置请求方法是不是异步asynctrue为异步, false为同步。AJAX存在的意义就是发异步请求,所以第三个参数永远传true

这里有个问题,就是IE中的缓存问题
IE浏览器中,如果通过Ajax发送GET请求,那么IE浏览器认为,同一个URL只有一个结果,如果地址没有发生变化,它就会把上一次返回的结果,直接返回。这样我们不能实时的拿到变化后的数据。如果要想我们拿到实时数据,必须保证每次的URL都是不一样的,有两种方式:
(1)Math.random();随机数
(2)new Date().getTime();1970.01.01至当前的毫秒数。
即在请求地址后面拼接上?t=随机数或者1970.01.01至当前的毫秒数
所以在IE中通过ajax发送get请求时,可以设置请求地址为:

xmlhttp.open("GET","ajax-get.txt?t=" + (new Date().getTime()),true);
//或
xmlhttp.open("GET","ajax-get.txt?t=" + Math.random(),true);
3. 发送请求

直接通过异步对象的send()发送请求

xmlhttp.send();

特别注意的是: 如果发送POST请求,请使用setRequestHeader()来添加HTTP请求头,并在send()方法中传递要发送的数据:

xmlhttp.open("POST","ajax_test.html",true); 
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 
xmlhttp.send("fname=Henry&lname=Ford");
4. 通过onreadystatechange监听状态变化

每当异步对象的readyState发生改变,就会触发onreadystatechange函数,当readyState变成为4时,表示当前状态是请求完毕的状态,同时当http的响应码status200300之间(包括200300)或为304时,表示ajax请求成功;当http状态码不是200300之间的数也不是304时,表示请求不成功

//4.监听状态变化
xmlhttp.onreadystatechange = function(){
 // 判断当前状态改变是请求完毕的状态吗
 if (xmlhttp.readyState === 4) {
    if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status == 304) {
        console.log("成功的接收到服务器返回的数据");
    }else{
        console.log("不成功!");
    }   
 }
}  
5. 处理返回的结果

如果成功,可通过异步对象的responseText属性来获取服务器返回的字符串

console.log(xmlhttp.responseText);

根据上述情况,如果每次请求都要手写以上五个步骤,那很麻烦,接下来,我们来封装一个方法ajax()用于发送请求

封装的时候,需要注意
(1)URL当中只能出现字母 数字 下划线和ASCII码,不能出现中文,可以使用encodeURIComponent()转码
(2)当我们利用我们的ajax放的发送一个请求到远处服务器时,我们需要等待远程服务器去响应我们的请求,等待远程服务器将响应的结果返回给我们,但是这个响应的速度是不确定的,因为响应的速度是由本地网络和远程服务器的网速等共同决定的,所以我们不可能一直等待服务器的响应。那么这里我们需要新增另外一个功能:设置超时时间的功能,即告诉它我的请求会等待多长的时间,如果这么长的时间内都没有响应我们发送的请求,那我就在这里自动的终止这次请求;

function ajax(type, url, obj, timeout, success, error) {
    //  0.将对象转换成字符串
    var str = objToString(obj);
    //  1.创建一个异步对象xmlhttp;
    var xmlhttp, timer;
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else {// code for IE6, IE5 
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    //  2.设置请求方式和请求地址; 
    // 判断请求的类型是POST还是GET
    if (type === 'GET') {
        xmlhttp.open(type, url + "?t=" + str, true);
        //  3.发送请求;
        xmlhttp.send();
    } else {
        //如果是post请求,需要设置请求头
        xmlhttp.open(type, url, true);
        // 注意:在post请求中,必须在open和send之间添加HTTP请求头:setRequestHeader(header,value);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        //  3.发送请求;
        xmlhttp.send(str);
    }
    //  4.监听状态的变化;
    xmlhttp.onreadystatechange = function () {
        clearInterval(timer);
        if (xmlhttp.readyState === 4) {
            if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status == 304) {
                //  5.处理返回的结果;
                success(xmlhttp);//成功后回调;
            } else {
                error(xmlhttp);//失败后回调;
            }
        }
    }
    //处理obj 
    function objToString(obj) {
        obj.t = new Date().getTime();
        var res = [];
        for (var key in obj) {
            //需要将key和value转成非中文的形式,因为url不能有中文。使用encodeURIComponent();
            res.push(encodeURIComponent(key) + " = " + encodeURIComponent(obj[key]));
        }
        return res.join("&");
    }
    //判断外界是否传入了超时时间
    if (timeout) {
        timer = setInterval(function () {
            xmlhttp.abort();//中断请求
            clearInterval(timer);
        }, timeout);
    }
}

在使用自己封装的代码的时候,感觉跟jQuery官方的ajax还是有一定的差异,所以还需要进一步完善

首先看第一个问题,传递多个参数,需要保持传递顺序。解决方案是可以改写成传递的是一个对象;因为对象里面的值,传递的是一个对象就不用考虑先后顺序,里面用的参数通过对象名.属性名的形式获取

第二,传递请求类型的区分大小写,jQuery官方的是大小写都可以;解决方案是可以使用toLowerCase()或者toUpperCase()将类型转成大写或小写再对比;

第三,我们传递的数据用的名字是objjQuery官方用的是data,语义更适合。所以将传递数据obj改成data

完善如下:

function ajax(option) {//type,url,obj,timeout,success,error将所有参数换成一个对象{}
    //  0.将对象转换成字符串
    var str = objToString(option.data);
    //  1.创建一个异步对象xmlhttp;
    var xmlhttp, timer;
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else {// code for IE6, IE5 
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    //  2.设置请求方式和请求地址; 
    // 判断请求的类型是POST还是GET
    if (option.type.toLowerCase() === 'get') {
        xmlhttp.open(option.type, option.url + "?t=" + str, true);
        //  3.发送请求;
        xmlhttp.send();
    } else {
        xmlhttp.open(option.type, option.url, true);
        // 注意:在post请求中,必须在open和send之间添加HTTP请求头:setRequestHeader(header,value);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        //  3.发送请求;
        xmlhttp.send(str);
    }
    //  4.监听状态的变化;
    xmlhttp.onreadystatechange = function () {
        clearInterval(timer);
        if (xmlhttp.readyState === 4) {
            if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status == 304) {
                //  5.处理返回的结果;
                option.success(xmlhttp);//成功后回调;
            } else {
                option.error(xmlhttp);//失败后回调;
            }
        }
    }
    //处理obj 
    function objToString(data) {
        data.t = new Date().getTime();
        var res = [];
        for (var key in data) {
            //需要将key和value转成非中文的形式,因为url不能有中文。使用encodeURIComponent();
            res.push(encodeURIComponent(key) + " = " + encodeURIComponent(data[key]));
        }
        return res.join("&");
    }
    //判断外界是否传入了超时时间
    if (option.timeout) {
        timer = setInterval(function () {
            xmlhttp.abort();//中断请求
            clearInterval(timer);
        }, timeout);
    }
}

最后传参形式变成

ajax({
   type: xxx,
   url: xxx,
   data: xxx,
   timeout:xxx,
   success: xxx,
   error:xxx
});

以上就是ajax相关的内容,基本功能是能实现,但跟jQuery的ajax还是差很多,考虑的也不全,想了解jQuery的ajax可以阅读以其源码,后面有时间我也会一起来看一下

相关文章

  • 一篇搞清AJAX及实现手动封装

    所谓AJAX就是异步JavaScript和XML,是一种无须加载整个网页就能实现更新部分网页的技术 那如何发送一个...

  • 手动promise封装ajax

    首先,定义传入 ajax函数的默认参数 使用方式如下:

  • AJAX POST请求实现/AJAX封装/node/RESTfu

    AJAX POST请求实现 AJAX封装 JSONP node.js 扩展

  • Ajax

    标签: Ajax 正文 一、实现一个原生Ajax 二、Ajax状态 三、将原生的 ajax 封装成 promise

  • Ajax的原生以及封装

    大家听过Ajax交互,可如何实现以及如何封装一个Ajax呢?今天就带大家来封装一个原生的Ajax; 喜欢请用你们的...

  • js原生ajax

    Ajax及封装Ajax详解参考传送门:https://blog.csdn.net/c__dreamer/artic...

  • ajax前后端交互原理(7)

    7.ajax函数封装 #7.1.实例引入 需求: 每秒钟请求一次服务器 获取到数据 实现: 把ajax进行封装 #...

  • ajax函数封装

    ajax函数封装 封装一个ajax

  • Ajax上

    一、封装ajax 二、调用封装好的ajax

  • 面试题

    axios和ajax的区别 axios是通过promise实现对ajax技术的一种封装axios可以运行nodej...

网友评论

    本文标题:一篇搞清AJAX及实现手动封装

    本文链接:https://www.haomeiwen.com/subject/qyjkektx.html