本篇文章会帮助你从根本上知道 ajax 的来路,但不会帮你解析它的具体封装。

实现一个AJAX异步调用和局部刷新

  1. 创建XMLHttpRequest对象,也就是创建一个异步调用对象
  2. 创建一个新的HTTP请求,并指定该HTTP请求的方法、URL
  3. 设置响应HTTP请求状态变化的函数

作为一个前端开发者,你必须先了解 XMLHttpRequest

XMLHttpRequest

XMLHttpRequest一种支持异步请求的技术,它是Ajax的核心

可以向服务器提出请求并处理响应,而不阻塞用户

可以在页面加载以后进行页面的局部更新

创建 XMLHttpRequest 对象

var xmlHttp;
if(window.XMLHttpRequest){
    xmlHttp = new XMLHttpRequest();
}else{
    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")
}
console.log(xmlHttp)

当然你也可以写个比较详细的判断,比如

function createXHR() {
    if (typeof XMLHttpRequest != "undefined") {
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject !== "undefined") {
        var xhrArr = ['Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.6.0',
                      'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0',
                      'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP.2.0']
        var len = xhrArr.length;
        var xhr;
        for (var i = 0; i < len; i++) {
            try {
                xhr = new ActiveXObject(xhrArr[i]);
                break;
            } catch (ex) {

            }
        }
        return xhr;
    }else {
        throw new Error('No XHR object availabel.')
    }
}
var xhr = createXHR();
console.log(xhr);

如何创建HTTP请求

  • 语法:open(method,url,async)
  • 功能:创建HTTP请求,规定请求的类型、URL及是否异步处理请求
  • 参数:

    • method:请求类型,GET or POST
    • url:地址
    • async:true(异步) or false(同步)

open方法不会向服务器发送真正请求,它相当于初始化请求并准备发送只能向同一个域中使用相同协议和端口的URL发送请求,否则会因为安全原因而报错。

xmlHttp.open("get", "./server/slider.json", true)
xmlHttp.open("post","./server/slider.json", true)

GET与POST的区别

与POST相比,GET 更简单也更快,并且在大部分情况下都能用,然而,在以下情况中,必须使用POST请求:

  • 无法使用缓存文件(更新服务器上的文件或数据库)
  • 向服务器发送大量数据(POST没有数据量限制)
  • 发送包含未知字符的用户输入时,POST比GET更稳定也更可靠

同步与异步的区别

同步:提交请求->等待服务器处理->处理完毕返回这个期间客户端浏览器不能干任何事

异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

如何发送请求

  • 语法:send(string)
  • 功能:将请求发送到服务器
  • 参数:string 仅用于 post 请求,仅在 post 请求时可以传入参数,不需要则发送 null,在调用 send 方法之后请求被发往服务器。

示例代码一并写在下方。

如何添加HTTP头

  • 如果需要像HTML表单那样POST数据,需使用 setRequestHeader() 来添加HTTP头,然后在 send() 方法中规定希望发送的数据
  • 语法:xmlHttp.setRequestHeader(header,value)
  • 使用:xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlHttp.open("get", "./server/slider.json?username=zhangsan&id=666", true)
xmlHttp.send(null)

xmlHttp.open("post","./server/slider.json", true)
// post请求参数
xmlHttp.send({username:"zhangsan",id:"666"})
// 请求头
xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");

设置响应HTTP请求状态变化的函数

在收到响应后相应数据会填充到XHR对象的属性,有四个相关属性会被填充:

  • responseText——从服务器进程返回数据的字符串形式
  • responseXML———从服务器进程返回的DOM兼容的文档数据对象
  • status——从服务器返回的数字代码,如 404(未找到) 、200(已就绪)
  • status Text——伴随状态码的字符串信息
// 响应XMLHttpRequest对象状态变化的函数,onreadystatechange在readystatechange属性发送改变时触发
xmlHttp.onreadystatechange = function () {
    // 异步调用成功,响应内容解析成功,可以在客户端调用
    if (xmlHttp.readyState === 4) {
        if ((xmlHttp.status >= 200 && xmlHttp.status < 300) || xmlHttp.status === 304) {
            // 获取服务器返回的数据
            console.log(xmlHttp.responseText);
        }
    }
}

JSON数据文本

JSON(javascript object notation)全称是javascript对象表示法,它是一种数据交换的文本格式,而不是一种编程语言,用于读取结构化数据,2001年由Douglas Crockford提出,目的是取代繁琐笨重的XML格式。

JSON的语法可以表示以下三种类型的值:

简单值

简单值使用与JavaScript相同的语法,可以在JSON中表示字符串、数值、布尔值和null

字符串必须使用双引号表示,不能使用单引号,数值必须以十进制表示,且不能使用NaN和Infinity

说明:JSON不支持JavaScript中的特殊值undefined

对象

对象作为一种复杂数据类型,表示的是一组有序的键值对儿,而每个键值对儿中的值可以是简单值,也可以是复杂数据类型的值

JSON中对象的键名必须放在双引号里面,因为JSON不是javascript语句,所以没有末尾的分号

说明︰同一个对象中不应该出现两个同名属性

数组

数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值

说明∶数组或对象最后一个成员的后面,不能加逗号

{
    "name": "BeJson",
    "url": "http://www.bejson.com",
    "page": 88,
    "isNonProfit": true,
    "address": {
        "street": "科技园路.",
        "city": "江苏苏州",
        "country": "中国"
    },
    "links": [
        {
            "name": "Google",
            "url": "http://www.google.com"
        },
        {
            "name": "Baidu",
            "url": "http://www.baidu.com"
        },
        {
            "name": "SoSo",
            "url": "http://www.SoSo.com"
        }
    ]
}

前面我们提到了responseText返回的是字符串,是不能供我们js代码正常使用的,因此我们需要将它转化为我们可以操作的数据类型,JSON对象中有两个方法可以让我们快速完成转换。

两个方法

parse()

  • 语法:JSON.parse()
  • 功能:用于将JSON字符串转化成对象

stringify()

  • 语法:JSON.stringify()
  • 功能:用于将一个值转为字符串,该字符串应该符合JSON格式,并且可以被 JSON.parse() 方法还原

JSON之所以流行,是因为可以把JSON数据结构解析为有用的javascript对象

JSON对象的stringify()和parse()这两个方法可以分别用于把JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript值

JavaScript的eval()类似于JSON.parse()方法,可以将json字符串转换为json对象,但是,eval()可以执行不符合JSON格式的代码,有可能会包含恶意代码,所以尽量少用

渲染数据,渲染的方式有很多种,比较简写的一般是使用字符串循环遍历来进行拼接后传入html,示例代码

 <div class="banner" id="banner"></div>

// 渲染数据
function renderDataToDom() {
    var img = data.slider,
        i, len = img.length,
        str = "",
        banner = document.getElementById("banner")
    for (i = 0; i < len; i++) {
        str += '<a href="' + img[i].linkUrl + '"><img src="./' + img[i].picUrl + '"></a>'
    }
    console.log(str)
    banner.innerHTML = str
}

jQuery的ajax方法

<div class="banner" id="banner"></div>
<script src="./js/jquery-1.7.1.js"></script>
<script>
    .ajax({
        url: "./server/slider.json", // 请求地址
        type: "get",                 // 请求类型
        async: true,                 // 同步异步
        dataType: "json",            // 返回数据类型
        success: function (data) {   // 请求成功后回调
            // 数据渲染
            renderDataToDom(data.slider)
        },
        error: function (error) {
            console.log(error)
        }
    })
    // 数据渲染
    function renderDataToDom(data) {
        var str = ""
        $.each(data, function (index, item) {
            str += `<a href="${item.linkUrl}"><img src="./${item.picUrl}"></a>`
        })
        $("#banner").html(str)
    }
</script>

解决跨域

跨域问题是比较经典的了,之前没了解过的可以看这里

众所周知:ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态页面、web服务、WCF,只要是跨域请求,一律不得通过。

下面介绍的是如何使用 JSONP 解决跨域

JSONP是 JSONwith Padding(填充式json) 的简写,是应用JSON的一种新方法,也是一种跨域解决方案。

直接用 XMLHttpRequest 请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp 正是利用这个特性来实现的。

JSONP 的原理

通过script标签引入js文件 -> js文件载入成功后 -> 执行我们在url参数中指定的函数

JSONP 的组成

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

// 封装JSONP
function getJSONP(url, callback) {
    if (!url) {
        return;
    }
    var r = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'],
        r1 = Math.floor(Math.random() * 10),
        r2 = Math.floor(Math.random() * 10),
        r3 = Math.floor(Math.random() * 10),
        name = 'getJSONP' + r[r1] + r[r2] + r[r3],
        // 使用getJSONP. 此处应该保持与函数名相同
        cbName = 'getJSONP.' + name;
    if (url.indexOf('?') === -1) {
        url += '?jsonp=' + cbName;
    } else {
        url += '&jsonp=' + cbName;
    }
    // 动态创建script标签
    var script = document.createElement('script');
    // 定义被脚本执行的回调函数
    // https://www.xn2001.com/?jsonp=getJSONP.getJSONPejg
    getJSONP[name] = function (data) {
        try {
            callback && callback(data);
        } catch (error) {
            console.log(error);
        } finally {
            // 最后删除该函数及script标签
            delete getJSONP[name];
            script.parentNode.removeChild(script)
        }
    }

    //定义script的src
    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);

}
getJSONP("https://class.imooc.com/api/jsonp", function (data) {
    console.log(data);
})

如何从js的角度理解工作原理?

通过拼接后请求的地址为:https://class.imooc.com/api/jsonp?jsonp=getJSONP.getJSONPejg -> 返回的数据为 getJSONP.getJSONPcjf+(json数据) -> 携带数据寻找到getJSONP函数下的getJSONPcjf函数 -> 将数据传出到回调函数供我们使用 -> 删除掉污染的src和函数等

所以JSONP并不是真正的ajax,利用的是调用js文件时则不受跨域的影响。

如何在 JQuery 中使用 JSONP,加个参数和改下数据返回类型 -> jsonp 、 dataType

$.ajax({
    url: "https://class.imooc.com/api/jsonp",
    type: "get",
    async: true,
    dataType: "jsonp",
    jsonp: "jsonp",
    success: function (data) {
        console.log(data);
        // 数据渲染
        renderDataToDom(data.slider)
    }
})

Last modification:June 13, 2021
如果觉得我的文章对你有用,请随意赞赏