一、ajax 基础

浏览器的技术
ajax Asynchronous javascript and xml

  • xml: 是可扩展标记语言,和 html 一样,可以清楚的表示层级。在 ajax 刚刚兴起的时候,为了表达数据的结构和层次,数据结构多是使用 xml;
  • 现在都是 json,json 也可以表达数据结构;
  1. JSON.parse() // json 格式字符串转对象
  2. JSON.stringify() // 对象转 JSON 格式的字符串
  • 现在的前端都是前后端分离的,即前端负责数据的绑定和维护;
  • 服务端渲染和全局刷新

在很久以前,没有 ajax 之前,都是前后端不分离的;前后端不分离是前端写好 html + css 结构,然后把 html 交给后端,然后利用服务端技术从服务器的数据库中把数据查出来,然后绑定到页面中,然后把绑定好数据的页面直接返回给浏览器,就是说浏览器拿的就是绑定好数据的页面 html(服务端渲染 SSR(Server-Side-Rendering));
但是这么干有一个问题,如果我这个页面中只有一部分内容是动态绑定的,如果我需要看到这部分内容,就需要刷新整个页面重新获取才行,因为绑定数据只有在服务器上才能进行。这种体验很不好,这种刷新整个页面获取数据的方式称为全局刷新;

  • 前后端分离

后来 ajax 诞生了,ajax 可以直接从服务器获取数据而不用刷新整个页面;发送一个 ajax 请求,等到请求结束后把数据通过前端手段把数据绑定到页面中(动态创建 dom + appendChild 或者字符串拼接 + innerHTML)。这种用 ajax 渲染数据的方式是局部刷新的。

  • ajax 的实例是可以向服务器发送请求的;

使用 ajax

  1. 创建一个 ajax 实例对象
  1. let xhr = new XMLHttpRequest();
  1. 可以通过 XMLHttpRequest 原型上的 open 方法打开一个路径
  1. xhr.open('get', 'https://www.easy-mock.com/mock/5d21a1b35b95ef4e9dd1a28c/example/myfirstmock', true);
  • open 方法的参数:

  • http-method: GET POST

  • url
  • async: true 表示异步,false 表示同步
  1. 监听 ajax 实例的 onreadystatechange 事件,当 ajax 发送请求时,会触发这个事件行为
  1. xhr.onreadystatechange = function () {
  2. // 如果 ajax 是异步执行的,这个函数会执行三次,三次的 readyState 分别为 x
  3. console.log(xhr.readyState); // 2 3 4
  4. // 为了确定拿到数据,我们不仅判断 xhr.readyState,还需要根据 xhr.status 来判断,xhr 使用的就是 http status,表示当前请求的状态;
  5. if (xhr.readyState === 4 && /^2\d{2}/.test(xhr.status)) {
  6. // xhr.readyState 为4表示 ajax 请求完成,xhr.status 是一个以2开头的三位数,表示请求成功,所以可以在获取服务端返回的数据
  7. }
  8. };
  1. 发送请求
  1. xhr.send(); // send 方法还可以传递参数
  • xhr.readyState 表示当前 ajax 实例对象的所处的状态

  • 0: 创建了一个 ajax 实例对象

  • 1: 已经调用 open 方法,打开了路径
  • 2: 客户端已经接收到服务端的信息(如果需要获取头信息中某些内容,可以在 readyState 为2时获取就可以)
    1. 客户端正在接收响应主体的数据
    1. 客户端已经全部接收服务端的数据

      二、ajax的请求方式

  1. let xhr = new XMLHttpRequest();
  2. xhr.open('get', 'aside.json', true);
  3. xhr.onreadystatechange = function () {
  4. if (xhr.readyState === 4 && /^2\d{2}/.test(xhr.status)) {
  5. console.log(xhr.responseText);
  6. }
  7. };
  8. xhr.send(JSON.stringify({username: 'mabin', pwd: '1233456'}));
  • xhr.open() 方法的第一个参数用于指定 http-method,即 http 的请求方式:

一般接口的请求方式由服务端提供,而且会在接口文档中说明

常见的请求方式:

=> GET: 一般用于从服务端获取数据,但是也可以向服务器传递少量的数据;

  • get 请求方式的特点
  1. 向服务器传递数据的方式:通过向接口末尾添加问号传参的方式传递,如: aside.json?name=mabinpwd=123456
  2. 由于浏览器的 url 地址是有长度限制的,IE 的 url 一般不超过 2k,谷歌的一般在 8k,超过的部分会自动被截掉,所以 get 请求传递的数据很小
  3. 参数直接暴露在 url 中,安全性低;
  4. get 请求容易产生缓存,为了防止缓存,一般在 url 末尾拼接一个随机数或者时间戳,因为浏览器发现 url 变化了,就会重新请求而不是使用之前已经缓存的数据;

=> POST 一般用于把数据传递给服务器或者传递大量的数据时

  1. post 把需要传递给服务器的数据放在请求体中传递给服务器
  2. 由于 post 数据放在请求体中,大小没有限制
  3. post 传递数据时把数据放在请求体中的,相对于 get 而言比较安全
  4. post 请求不会默认走缓存

其他请求方式

  • DELETE: 删除数据
  • HEAD: 获取响应头,不需要响应体
  • PUT: 修改某些内容
  • OPTIONS: 查询服务器的支持的http请求方式
  • TRACE: 回显服务器收到的请求,一般用于测试

三、ajax 的同步和异步

  • js 是单线程的:每次只能执行一个任务
  • 浏览器是多线程的,可以同时执行多个任务;
  1. let data = null;
  2. let xhr = new XMLHttpRequest();
  3. xhr.open('get', 'aside.json', true);
  4. xhr.onreadystatechange = function () {
  5. console.log(xhr.readyState); // false 时只输出 4
  6. console.log(xhr.readyState); // true 时输出2 3 4
  7. data = xhr.responseText;
  8. };
  9. xhr.send();
  10. function bindHTML(data) {
  11. // 绑定 html 的方法
  12. }

为什么会有异步的 ajax?

如果页面中有5个请求

  1. // 1. 1s
  2. // 2. 2s
  3. // 3. 3s
  4. // 4. 4s
  5. // 5. 5s
  • 如果使用同步的,同步任务都是阻塞的,上一个执行不完下一个不能开始,如果这些接口没有必然关系,用户需要 15s 才能看到,这个用户体验很不好。
  • 如果使用异步的,第一个发出后随即就开始第二个,然后第三个,因为异步不是阻塞的,后面的不用等待前面的完成(这样子看起来很像同时发送了5个请求),这样一来用时5s就可以了

所以一般情况下 ajax 使用异步的;

  • 但是使用异步的也有一个问题,如果这5个接口是互相依赖的,比如第二个依赖第一个返回的数据,第三个依赖第二个返回的数据这种情况使用异步,顺序是无法保证的,因为异步任务是谁先到达执行条件谁先执行;