Ajax(一) - 原生Ajax

144 阅读6分钟

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

Asynchronous Javascript And XML

• AJAX 就是浏览器提供的一套 API,可以通过 JavaScript 调用,从而实现通过代码控制请求与响应。实现通过 JavaScript 进行网络编程。

• XML:最早在客户端与服务端之间传递数据时所采用的数据格式

原生Ajax

发送 ajax 请求步骤:

  1. 创建 XMLHttpRequest 类型的对象

  2. 准备发送,打开与一个网址之间的连接

  3. 执行发送动作

  4. 指定 xhr 状态变化事件处理函数

    // 1.创建一个 XMLHttpRequest 类型的对象  --- 相当于打开了一个浏览器
    var xhr = new XMLHttpRequest();
    
    // 2.打开一个与网址之间的连接  --- 相当于在地址栏输入网址
    xhr.open("GET","https://jsonplaceholder.typicode.com/users");
    
    // 3.通过连接发送一次请求 --- 相当于点击回车或者超链接
    xhr.send(null);
    
    // 4.指定 xhr 状态变化事件处理函数   --- 相当于处理网页呈现后的操作
    xhr.onreadystatechange = function () {
      // 通过判断 xhr 的 readyState ,确定此次请求是否完成
      if (this.readyState === 4) {
        console.log(this.responseText)
      }
    }

XMLHttpRequest 类型对象

AJAX API 中核心提供的是一个 XMLHttpRequest 类型,所有的 AJAX 操作都需要使用到这个类型。

标准浏览器: var xhr = new XMLHttpRequest();

IE6 兼容: xhr = new ActiveXObject("Microsoft.XMLHTTP");

    // 1.创建一个 XMLHttpRequest 类型的对象 
    var xhr = null;
    
    // 兼容写法
    if (window.XMLHttpRequest) {
      // 标准浏览器返回true
      xhr = new XMLHttpRequest();
    } else {
      // IE 6 浏览器
      xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }

open() 方法开启请求

本质上 XMLHttpRequest 就是 JavaScript 在 Web 平台中发送 HTTP 请求的手段,所以我们发送出去的请求仍然是 HTTP 请求,同样符合 HTTP 约定的格式。

语法:xhr.open(method, url)

  • method:要使用的HTTP方法,比如「GET」、「POST」、「PUT」、「DELETE」、等。

  • url:要向其发送请求的 URL 地址,字符串格式。

    // 2.open() 方法开启请求
    // xhr.open("GET","https://jsonplaceholder.typicode.com/users?id=1");
    xhr.open("POST","https://jsonplaceholder.typicode.com/users");

setRequestHeader() 方法设置请求头

此方法必须在 open() 方法和 send() 之间调用。

一般 get 方法不需要设置,而 post 方法必须设置

语法:xhr.setRequestHeader(header, value);

  • header: 一般设置 “Content-Type” ,传输数据类型,即服务器需要我们传送的数据类型

  • value: 具体的数据类型,常用 "application/x-www-form-urlencoded" 和 "application/json"。

    // 设置请求头
    // 一般 get 方法不需要设置,而 post 方法必须设置
    xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

send() 方法发送请求

用于发送 HTTP 请求

语法:xhr.send(body)

body:在XHR请求中要发送的数据体,根据请求头中的类型进行传参。

如果是 GET 方法,无需设置数据体,可以传 null 或者不传参。

    // 3.send() 方法发送一次请求
    // 如果是 get 方法请求,不需要再 send 中传参数,它如果想传参数,直接写在网址上
    // xhr.send(null);
    xhr.send("name=harry&age=19");

readyState 属性

readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态,由于 readystatechange 事件是在 xhr 对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次,所以我们有必要了解每一个状态值代表的含义:

image.png

image.png

事件处理函数

一般我们都是在 readyState 值为 4 时,执行响应的后续逻辑。

    xhr.onreadystatechange = function () {
      // 通过判断 xhr 的 readyState ,确定此次请求是否完成
      if (this.readyState === 4) {
        console.log(this.responseText)
      }
    }

同步与异步

xhr.open() 方法第三个参数要求传入的是一个 boolean 值,其作用就是设置此次请求是否采用异步方式执行

  • 默认为 true 异步,如果需要同步执行可以通过传递 false 实现

如果采用同步方式执行,则代码会卡死在 xhr.send() 这一步, 直到所有数据接受完成才会继续向下执行.

建议:

为了让这个事件可以更加可靠(一定触发),在发送请求 send() 之前,一定是先注册readystatechange, 这样不论是同步或异步都能触发成功:

    xhr.open("GET","https://jsonplaceholder.typicode.com/users",false);
    // 如果设置了同步加载,程序会卡在 send 部分
    xhr.onreadystatechange = function () {
      // 通过判断 xhr 的 readyState ,确定此次请求是否完成
      if (this.readyState === 4) {
        console.log("请求成功")
      }
    }
    // 3.通过连接发送一次请求
    xhr.send(null);

了解同步模式即可,切记不要使用同步模式

原生 AJAX 具体用法

GET 请求

• 通常在一次 GET 请求过程中,参数传递都是通过 URL 地址中的 ? 参数传递。

• 一般在 GET 请求中,无需设置请求头

• 无需设置响应体,可以传 null 或者干脆不传

    // 发送 GET 请求
    xhr.open("GET", "http://localhost:3000/users?age=19");
    xhr.send(null);
    xhr.onreadystatechange = function () {
      if (this.readyState === 4) {
        console.log(this.responseText);
      }
    }

image.png

POST 请求

• POST 请求过程中,都是采用请求体承载需要提交的数据。

• 需要设置请求头中的 Content-Type,以便于服务端接收数据

• 需要提交到服务端的数据可以通过 send 方法的参数传递

方法一: urlencoded

    var xhr = new XMLHttpRequest();
    // post 请求
    xhr.open("POST","http://localhost:3000/users");
    // 设置请求头
    xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    xhr.send("name=lily&age=19&class=2");
  
    xhr.onreadystatechange = function () {
      if (this.readyState === 4) {
        console.log(this.responseText);
      }
    }

方法二: json

    var xhr = new XMLHttpRequest();
    // post 请求
    xhr.open("POST","http://localhost:3000/users");
    // 设置请求头
    xhr.setRequestHeader("Content-Type","application/json");
    // xhr.send(`{
    //   "name": "lulu",
    //   "age": 18,
    //   "class": 2
    // }`);
    xhr.send(JSON.stringify({
      "name": "harry",
      "age": 18,
      "class": 1
    }));
    xhr.onreadystatechange = function () {
      if (this.readyState === 4) {
        console.log(this.responseText);
      }
    }

处理响应数据渲染

客户端中拿到请求的数据过后最常见的就是把这些数据呈现到界面上。

如果数据结构简单,可以直接通过字符串操作(拼接)的方式处理. 但是如果数据过于复杂,字符串拼接维护成本太大,就不推荐了, 可以使用模版引擎或者 ES6 提供的模板字符串.

data中的数据:

image.png

        // 讲获取的响应体的字符串转为对象
        var data = JSON.parse(this.responseText)
        console.log(data);
        var str = "";
        
        // 循环遍历数组
        for (var i = 0 ; i < data.length ;i++) {
          // 进行字符串拼接 
          // str += "<tr><td>" + data[i].id + "</td><td>" + data[i].name + "</td><td>" + data[i].age + "</td><td>" + data[i].class + "</td></tr>";
          
          // 使用 模板字符串 进行拼接
          str += `<tr>
            <td>${data[i].id}</td>
            <td>${data[i].name}</td>
            <td>${data[i].age}</td>
            <td>${data[i].class}</td>
          </tr>`
        }
        box.innerHTML += str;
      }

封装 AJAX 函数

这里主要是为了了解封装的过程,一般情况在开发中都是使用第三方提供的 AJAX 库,因为它们可能更加严谨。

为了在后续的开发过程中可以更方便的使用这套 API,一般的做法都是将其封装到一个函数中以便调用。

    // 封装自己的 Ajax 函数
    /**
     * 参数1:{string}    method  请求方法
     * 参数2:{string}    url     请求地址
     * 参数3:{Object}    params  请求参数
     * 参数4:{function}  done    请求完成后执行的回调函数
   */ 
    function ajax(method, url, params, done) {
      // 统一将方法中的字母转大写,便于后面判断
      method = method.toUpperCase();
      // 书写 IE 6 的兼容
      var xhr = window.XMLHttpRequest 
      ? new XMLHttpRequest() 
      : new ActiveXObject("Microsoft.XMLHTTP");
      // 将对象格式的参数转为 urlencoded的格式
      var pairs = [];
      for (var k in params) {
        pairs.push(k + "=" + params[k]);
      }
      var str = pairs.join("&");
      // 判断是否是 get 方法,需要更改 url 的值
      if (method === "GET") {
        url += "?" + str;
      }
      // 创建打开一个连接
      xhr.open(method, url);
      var data = null;
      // 如果是 post 方法,需要设置请求头,还有请求体
      if (method === "POST") {
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        data = str;
      }
      xhr.send(data);
      // 执行回调函数
      xhr.onreadystatechange = function () {
        if (this.readyState !== 4) return;
        // 执行外部传进来的回调函数即可
        // 需要用到响应体
        done(JSON.parse(this.responseText));
      }
    }
    // 调用函数
    ajax("GET", "http://localhost:3000/users",{"id": 1},function (data) {
      console.log(data);
    });
    // POST会新增一条数据
    ajax("POST", "http://localhost:3000/users",{"name": "john","age": 19,"class": 2},function (data) {
      console.log(data);
    });