Ajax 基础

232 阅读3分钟

Ajax,全称 Asynchronous JavaScript and XML,即异步 JavaScript 和 XML。Ajax 是浏览器和服务器之间的一种异步通信方式,最大的特点就是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。

网页传统请求

网页中传统的请求:

  • 超链接
  • 表单
  • window.location.href

传统的请求的缺点

  • 会使得页面刷新
  • 如果请求耗时长,页面会处于空白页
  • 只能线性地同步调用请求

Ajax请求

Ajax请求的特点:

  • 局部更新页面,而不会刷新整个页面
  • 能够异步发起请求,不影响用户操作
  • 能够一次性发起多个请求,每个请求单独一个线程

Ajax请求的切点:

  • 没有浏览历史记录(不能回退)
  • 存在同源跨域问题
  • SEO不友好(因为数据是由Ajax请求动态获取的,不在网页源代码中)

XMLHttpRequest对象

XMLHttpRequest 是由浏览器提供的对象,是实现 Ajax 的一种方式,Ajax 请求与响应的核心都与它相关。

readyState

readyState是一个记录XMLHttpRequest对象的状态:

  • 0,请求未初始化
  • 1,已连接到服务器
  • 2,请求已收到
  • 3,请求处理中
  • 4,请求已完成,响应已就绪

onreadystatechange

readyState发生改变时,触发回调函数。

status

HTTP状态码

response

响应体

responseType

设置响应体数据类型

  • arraybuffer
  • blob
  • document
  • json
  • text

responseText

响应数据,文本类型

open()

初始化请求,打开通道,方法参数为open(method, url, async, user, psw)

  • method,请求方法,GET/POST
  • url,请求地址
  • async,是否异步请求,true/false
  • username,服务器认证用户名
  • password,服务器认证密码

setRequestHeader()

用于设置请求头

  • setRequestHeader('Content-Type', '');

send()

用于发起请求

Ajax请求示例

Ajax get请求

  1. <input>作为发起请求的按钮
  2. <div>作为渲染的响应数据
<input type="button" id="btn" value="click here">
<div id="d">将要渲染的数据区</div>
  1. 获取 XMLHttpRequest 对象
  2. 在 XMLHttpRequest 对象状态回调函数中编写请求逻辑
  3. 打开请求通道,初始化请求
  4. 发起请求
$('#btn').click(()=>{
    // 1.获取 XMLHttpRequest 对象
    const xhr = new XMLHttpRequest();
  
    // 2.XMLHttpRequest 对象状态回调
    xhr.onreadystatechange = ()=> {
      console.log('readyState: ' + xhr.readyState);
      // 6.1 当请求完成时
      if (xhr.readyState === 4) {
          // 6.2 当请求成功时
          if (xhr.status === 200) {
              console.log(xhr.responseText);
              // 6.3 渲染数据
              $('#d').text(xhr.responseText);
          }
      }
    };
  
    // 3.打开请求通道
    xhr.open('GET', './data.json', true);
  
    // 5.发起请求
    xhr.send();
});

Ajax get带参数请求

  1. get请求参数在路径后拼接?name=value&name=value...
$('#btn').click(()=>{
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = ()=> {
      console.log('readyState: ' + xhr.readyState);
      if (xhr.readyState === 4) {
          if (xhr.status === 200) {
              console.log(xhr.responseText);
              $('#d').text(xhr.responseText);
          }
      }
    };
    xhr.open('GET', './data.json?timestamp=' + Date.now(), true);
    xhr.send();
});

Ajax post表单

  1. 模拟表单提交需要设置请求头Content-Type: application/x-www-form-urlencoded
  2. 表单数据在send()中以urlencoded格式传递
$('#btn').click(()=>{
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = ()=> {
      console.log('readyState: ' + xhr.readyState);
      if (xhr.readyState === 4) {
          if (xhr.status === 200) {
              console.log(xhr.responseText);
              render(xhr.responseText);
          }
      }
    };
    xhr.open('POST', 'https://code.jquery.com/jquery-3.7.1.min.js', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send('timestamp=' + Date.now());
});

在控制台中请求的数据格式

Ajax 处理JSON格式响应数据

  1. 处理JSON格式响应数据可以设置responseType=json,表示响应体是JSON格式数据;
  2. 获取数据时直接访问xhr.response
$('#btn').click(()=>{
  const xhr = new XMLHttpRequest();
  xhr.onreadystatechange = ()=> {
    console.log('readyState: ' + xhr.readyState);
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        console.log(xhr.response);
        render(JSON.stringify(xhr.response));
      }
    }
  };
  xhr.responseType = 'json';
  xhr.open('get', './data.json?timestamp=' + Date.now(), true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  xhr.send();
});

Ajax请求超时/网络异常

  • 通过ontimeout回调处理请求超时
  • 通过onerror回调处理网络异常
$('#btn').click(()=>{
  const xhr = new XMLHttpRequest();
  // 请求超时
  xhr.timeout = 2000;
  xhr.ontimeout = ()=> {
    alert('请求超时');
  };
  // 网络异常
  xhr.onerror = ()=> {
    alert('服务器异常');
  };
  xhr.open('get', './data.json?timestamp=' + Date.now(), true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  xhr.send();
});

Ajax请求中止

  • 通过abort函数中止请求
$('#btn').click(()=>{
  const xhr = new XMLHttpRequest();
  xhr.open('get', './data.json?timestamp=' + Date.now(), true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  xhr.send();
  // 请求中止
  xhr.abort();
});

请求抖动问题

请求抖动就是在短时间内多次发起同一个请求。为了避免请求抖动可以这样处理:

  1. 请求前判断是否有请求中,如有则中止请求
  2. 设置变量标识请求处于发送中
  3. 在请求状态回调中处理完成请求时设置变量标识为无请求
// 设置一个是否发送中的标识
let isSending = false;
let xhr = null;
$('#btn').click(()=>{
  // 已有发送中的请求则中止
  if (isSending) xhr.abort();
  xhr = new XMLHttpRequest();
  // 发送中
  isSending = true;
  xhr.onreadystatechange = ()=> {
    if (xhr.readyState === 4) {
      // 完成请求,设置发送中标识为false
      isSending = false;
      if (xhr.status === 200) {
        render(JSON.stringify(xhr.response));
      }
    }
  };
  xhr.open('get', './data.json?timestamp=' + Date.now(), true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  xhr.send();
});

低版本IE缓存问题

HTTP协议中规定GET请求是需要缓存的,当前后两次请求的路径完全一样时,后一次请求会直接从浏览器缓存中给直接获取前一次缓存的数据。

为避免缓存问题可以在请求URL的参数中加时间戳或随机数。

jQuery发送Ajax请求

参考《jQuery基础》

Axios发送Ajax请求

Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js。在客户端 (浏览端) 中 Axios 同样是使用 基于 XMLHttpRequest 发起 Ajax 请求。

引入axios.js

<script src="https://unpkg.com/axios@1.1.2/dist/axios.min.js"></script>

axios get请求

axios.get(url [, config])

  • url,请求地址
  • config,可以设置paramsheader
$('#btn').click(()=>{
  // axios.get(url, {params, headers})
  axios.get('./data.json', {
    params: {
      timestamp: Date.now()
    },
    headers: {
      name: 'wei'
    }
  }).then(value => {
    console.log(value);
  });
});

axios post请求

axios.post(url, data [, config])

  • url,请求地址
  • data,请求数据
  • config,可以设置paramsheader
$('#btn').click(()=>{
  // axios.post(url, data, {params, headers})
  axios.post('./data.json', {
    name: 'wei'
  }, {
    params: {
      timestamp: Date.now()
    },
    headers: {
      ['Content-Type']: 'application/json'
    }
  }).then(value => {
    console.log(value);
  });
});

axios get/post请求

axios({method, url [data, config]})

  • method,请求方法
  • url,请求地址
  • data,请求数据
  • config,可以设置paramsheader
$('#btn').click(()=>{
  axios({
    method: 'POST',
    url: './data.json',
    params: {
      timestamp: Date.now()
    },
    headers: {
      ['Content-Type']: 'application/json'
    },
    data: {
      name: 'wei'
    }
  }).then(value => {
    console.log(value);
  });
});

fetch发送Ajax请求

fetch()是一个全局静态方法。

fetch(input [, {init}])

  • input,请求地址
  • init,可以设置methodheadersbody
$('#btn').click(()=>{
  fetch('./data.json', {
    method: 'POST',
    headers: {
      ['Content-Type']: 'application/json'
    },
    body: JSON.stringify({
      name: 'wei'
    })
  }).then(response => {
    return response.json();
  }).then(result => {
    console.log(result);
  });
});