Ajax

# Ajax

Asynchronous JavaScript and XML(异步JavaScript和XML)

不是某种编程语言,是一种在无需重新加载整个网页的情况之下能够更新部分网页的技术。

[TOC]

# 一、初识Ajax

无须刷新页面即可从服务器获取数据。

# 1.1 手写Ajax

// 建立异步请求的过程(4个步骤):
// 1.new一个XHR对象
// XMLHttpRequest对象:实例化一个对象就可以实现异步操作
let request = new XMLHttpRequest();
// 2.调用open方法
// 用get方法异步打开get.php
request.open("GET","get.php",true);
// 3.send一些数据
// 发送请求头信息
request.send('a=1&b=2');
// 4.对过程进行监听,来知道服务器是不是正确地做出了响应,接着可以做一些事情
//(监听readyState,响应成功可以做一些事情,比如获取服务器响应的内容在页面上做一些呈现)
//通过onreadystatechange事件 ,对readyState属性进行监听即对服务器的响应进行监听,
//readyState===4响应完成;
//status===200,请求成功。
request.onreadystatechange = function() {
    if(request.readState === 4 && request.status === 200){
        //做一些事情
        console.log(request.responseText);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

使用ajax获取某一文本文件的内容,节省用户操作,时间,提高用户体验,减少数据请求;传输获取数据。

# 二、创建Ajax

# 2.1 XMLHttpRequest的工作原理

# 2.1.1 创建XMLHttpRequest 对象

# 2.1.2 使用open方法设置请求的参数open(method, url, 是否异步)

  • method:规定HTTP发送请求的方式是get还是post,不区分大小写,一般来说用大写

  • url:请求地址(相对地址或绝对地址)

  • async:同步/异步(false/true),默认是异步也就是true,可以不用填写。若设为false则浏览器会警告该方式对用户体验不好。

# 2.1.3 发送请求

  • send(string):发送到服务器。

    • 在请求体的位置发送。
  • 该参数可以填或者不填-----get方法不填或填null,post:一般要填。

    • 如果想要使用post提交数据,必须添加此行:xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

# 2.1.4 注册事件

注册 onreadystatechange 事件后,每当 readyState 属性改变时,就会调用 onreadystatechange 函数。

# 2.1.4.1 readyState
  • 表示请求/响应过程的当前活动状态。
数值 阶段 具体表现
0 未初始化 尚未调用open()方法
1 启动 已调用open()方法,尚未调用send()方法
2 发送 已调用send()方法,尚未接收响应
3 接收 已经接收到部分响应数据
4 完成 已接收全部响应数据,可接收全部响应数据

# 2.1.5 获取返回的数据,更新UI

XMLHttpRequest取得响应

  • responseText:获得字符串形式的响应数据
  • responseXML:获得XML形式的响应数据(比较少)
  • status和statusText:以数字和文本形式返回HTTP状态码
  • getAllResponseHeader():获取所有的响应报头
  • getResponseHeader():查询响应中的某个字段的值

# 2.2 兼容性处理

//IE兼容性处理:浏览器特征检查。检查该浏览器是否存在XMLHttpRequest这个api,没有的话,就用IE的api
var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP');
1
2

# 2.3 事件的触发条件

来自参考教程:你真的会使用XMLHttpRequest吗? (opens new window)

事件 触发条件
onreadystatechange 每当xhr.readyState改变时触发;但xhr.readyState由非0值变为0时不触发。
onloadstart 调用xhr.send()方法后立即触发,若xhr.send()未被调用则不会触发此事件。
onprogress xhr.upload.onprogress在上传阶段(即xhr.send()之后,xhr.readystate=2之前)触发,每50ms触发一次;xhr.onprogress在下载阶段(即xhr.readystate=3时)触发,每50ms触发一次。
onload 当请求成功完成时触发,此时xhr.readystate=4
onloadend 当请求结束(包括请求成功和请求失败)时触发
onabort 当调用xhr.abort()后触发
ontimeout xhr.timeout不等于0,由请求开始即onloadstart开始算起,当到达xhr.timeout所设置时间请求还未结束即onloadend,则触发此事件。
onerror 在请求过程中,若发生Network error则会触发此事件(若发生Network error时,上传还没有结束,则会先触发xhr.upload.onerror,再触发xhr.onerror;若发生Network error时,上传已经结束,则只会触发xhr.onerror)。注意,只有发生了网络层级别的异常才会触发此事件,对于应用层级别的异常,如响应返回的xhr.statusCode4xx时,并不属于Network error,所以不会触发onerror事件,而是会触发onload事件。

###2.4 事件的触发顺序

# 2.4.1 请求一切正常

  1. 触发xhr.onreadystatechange(之后每次readyState变化时,都会触发一次)
  2. 触发xhr.onloadstart(上传阶段开始)
  3. 触发xhr.upload.onloadstart
  4. 触发xhr.upload.onprogress
  5. 触发xhr.upload.onload
  6. 触发xhr.upload.onloadend(上传结束,下载阶段开始)
  7. 触发xhr.onprogress
  8. 触发xhr.onload
  9. 触发xhr.onloadend

# 2.4.2 发生abort/timeout/error异常的处理

在请求的过程中,有可能发生 abort/timeout/error这3种异常。那么一旦发生这些异常,xhr后续会进行哪些处理呢?后续处理如下:

  1. 一旦发生aborttimeouterror异常,先立即中止当前请求
  2. readystate 置为4,并触发 xhr.onreadystatechange事件
  3. 如果上传阶段还没有结束,则依次触发以下事件:
    • xhr.upload.onprogress
    • xhr.upload.[onabort或ontimeout或onerror]
    • xhr.upload.onloadend
  4. 触发 xhr.onprogress事件
  5. 触发 xhr.[onabort或ontimeout或onerror]事件
  6. 触发xhr.onloadend 事件

# 三、Ajax跨域处理

  • Ajax由于受同源策略限制而不能跨域。但跨域时,服务器能正常返回资源,但会被浏览器拦截,需要服务器设置access-control-allow-origin才能通过。
const http=require('http');

let allowOrigin={
    'http://localhost': true,
    'http://aaa.com': true,
    'https://aaa.com': true,null': true	// 为了支持本地文件设的
}

http.createServer((req, res)=>{
    let {origin}=req.headers;

    if(allowOrigin[origin]){
        res.setHeader('access-control-allow-origin', '*');
    }

    res.write('{"a": 12, "b": "Blue"}');
    res.end();
}).listen(8080);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 四、Fetch

很多情况下我们只需要使用ajax,但是却需要引入整个jquery,这非常的不合理,于是便有了fetch的解决方案。

fetch号称是ajax的替代品,它的API是基于Promise设计的。

# 5.1 与jQuery.ajax()的不同

  • 仅当网络故障时或请求被阻止时,才会被标记reject。即使接收的HTTP状态码是404或500,也会将Promise状态标记为resolve
  • 默认情况下,fetch 不会从服务端发送或接收任何 cookies, 如果站点依赖于用户 session,则会导致未经认证的请求(要发送 cookies,必须设置 credentials: 'include')。

# 5.2 读取文件

fetch读取文件是一次性读取的,所以不适用于读取视频,比较适用于小文件。

window.onload=function (){
    let oBtn=document.getElementById('btn1');
    oBtn.onclick=async function (){
        // 读取文本
        //1.请求
        let res1=await fetch('data/1.txt');
        //2.解析
        let str=await res1.text();
        alert(str);
        // 读取json文件
        //1.请求
        let res2=await fetch('data/1.json');
        //2.解析
        let json=await res2.json();
        console.log(json);

        // 读取图片
        //1.请求
        let res=await fetch('data/1.png');
        //2.解析
        // Blob 对象表示一个不可变、原始数据的类文件对象。
        // binary large object 二进位大物件
        let data=await res.blob();
        // 将数据放进一个临时文件,返回临时路径
        let url=URL.createObjectURL(data);
        oImg.src=url;
    };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28