Ajax 的执行流程以及原生 JS 封装一个 Ajax

本文介绍了Ajax的工作流程,包括怎样使用XMLHttpRequest发送HTTP请求,处理服务器响应,以及通过原生JS封装一个简单的Ajax示例。强调了异步请求的处理和状态检查,同时提供了一个GET请求的实例。
摘要由CSDN通过智能技术生成

Ajax 的执行流程以及原生 JS 封装一个 Ajax

1.引言

Ajax(Asynchronous JavaScript and XML)即异步的 JavaScript 与 XML,它不是一种语言,它是一组需要一起协同工作的技术。另外虽然名字中有 XML,但是 Ajax 通信与数据格式无关,实际上我们通常用 JSON 格式的数据来代替。

传统的 Web 应用允许用户端填写表单(form),当提交表单时就向网页服务器发送一个请求。服务器接收并处理传来的表单,然后送回一个新的网页,但这个做法浪费了许多带宽,因为在前后两个页面中的大部分 HTML 码往往是 相同 的。由于每次应用的沟通都需要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这导致了用户界面的回应比本机应用慢得多。

Ajax 技术的核心是 XMLHttpRequest 对象 (简称 XHR),XHR 为向服务器发送请求和解析服务器相应提供了流畅的接口。能够以异步的方式从服务器获取更多的信息,也就意味着用户单击后,可以 不用刷新整个页面也能获取到新数据 。也就是说,可以使用 XHR 对象获取新的数据,然后再通过 DOM 将数据插入到页面中。

2.Ajax 工作流程

在这里我不考虑 IE7 之前的版本,有兴趣的同学可以自己去看 JS 高程上对 IE7 之前兼容性的实现。

S1. 怎样发送 http 请求

通过 XMLHttpRequest 构造函数就可以在浏览器中创建一个 XHR 对象,通过该对象就可以向服务器发送一个 http 请求。

var xhr = new XMLHttpRequest();

当我们发送完一个请求后,会收到响应,我们要告诉 XHR 对象由哪一个 JavaScript 函数处理响应。其中,XMLHttpRequest.onreadystatechange 会在 XMLHttpRequest 的 readyState 属性发生改变时触发相关事件函数,函数既可以是命名的。

xhr.onreadystatechange = nameOfTheFunction;

需要注意的是函数名后没有参数,因为我们只是把一个引用赋值给了函数,而不是真正的调用了它。

当然我们也可以通过匿名函数处理相关响应:

xhr.onreadystatechange = function() {
  // 此处处理服务器的响应
};

接下来我们需要调用 XHR 对象的 open()和 send()方法分别对应着初始化和发送一个请求。

xhr.open("GET", "http://www.example.org/example.txt", true);
xhr.send();

其中 open()方法 并不会 真正发送请求,而只是启动一个请求以备发送。 XMLHttpRequest.open()方法接受三个参数:

xhr.open(method, url, async);
  • method 要使用的 HTTP 方法,比如「GET」、「POST」、「PUT」、「DELETE」、等,一定要保证这些方法是大写字母,否则其他一些浏览器(比如 FireFox)可能无法处理这个请求。

  • url 一个表示要向其发送请求的 URL。由于安全原因(同源策略),默认不能调用第三方 URL 域名,即不能跨域请求(如果非要跨域请求也是有办法的,后续我会写一篇关于跨域的。)

  • async 一个可选的布尔参数,默认为 true,表示要不要异步执行操作。如果值为 false,则代表同步请求,send()方法直到前面响应到达后继续执行,通俗话说就是在那干等。如果为 true(默认),则为异步操作,会在请求发送后立即执行。

XMLHttpRequest.send() 方法接受一个可选的参数,将其作为请求主体;如果请求方法是 GET 或者 HEAD,则应将请求主体设置为 null。如果是 POST 请求的话。发送表单数据时应该用服务器可以解析的格式,像查询语句,或者其他格式, 类似 multipart/form-data,JSON,XML 等。

还有非常重要的一点是,如果使用 POST 方法,应该在调用 send()方法之前使用 setRequestHeader() 方法设置 Content-Type 头部来指定数据流的 MIME 类型。曾经掉进这个坑…

假如我们调用 send() 方法获取表单数据那么应该这样写:

xhr.open("GET", "http://www.example.org/example.txt", true);
// 发送合适的请求头信息
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send();

S2. 处理服务器响应

假设我们发送的是异步请求,JavaScript 会继续执行,而不用等待响应。我们可以检测 XHR 对象的 readyState 属性,该属性表示请求/响应过程的当前活动状态,这些状态值如下图所示:

状态码

通常我们对 readyState 值为4的阶段感兴趣,因为此时所有的数据已经就绪。

xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    // Everything is good, the response was received.
  } else {
    // Not ready yet.
  }
};

接下来我们要检测 HTTP 响应的 response code 来区别对待成功或者不成功的 Ajax 调用。

if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      // Perfect!
    }
  } else {
    // There was a problem with the request.
  }

状态码 304 代表着请求的资源并没有被修改,可以直接使用浏览器缓存的版本,所以意味着响应也是有效的。

当我们检查完请求状态和 HTTP 响应码后,我们就可以用服务器返回的数据做接下来的事情了:

  • xhr.responseText -作为响应主体被返回的文本

  • httpRequest.responseXML -以 XMLDocument 对象方式返回,之后就可以使用 JavaScript 来处理

S3 一个简单的例子(以 GET 为例)

用户点击页面上的 “Make a request” 按钮,然后以 Ajax 方式 alert() test.html 文件内容。

<button id="ajaxButton" type="button">Make a request</button>
<script>
(function() {
  // 监听按钮点击事件
  document.getElementById("ajaxButton").addEventListener('click', makeRequest);

  function makeRequest() {
    // 创建xhr对象
    var xhr = new XMLHttpRequest();

    if (!xhr) {
      alert('Giving up :( Cannot create an XMLHTTP instance');
      return false;
    }
    xhr.onreadystatechange = alertContents;
    xhr.open('GET', 'test.html');
    xhr.send(null);
  }

  function alertContents() {
  try {
    // 检测readyState状态
    if (xhr.readyState === 4) {
      // 检测HTTP响应码
      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        alert(xhr.responseText);
        } else {
        alert('There was a problem with the request.');
        }
      }
    }
  catch( e ) {
    alert('Caught Exception: ' + e.description);
    }
  }
})();
</script>

3.手动封装

function Ajax(obj) {
  this.type = obj.type || "";
  this.url = obj.url || "";
  this.callback = obj.callback || "";
  this.data = obj.data || "";
}

Ajax.prototype.send = function(type, url, callback, data) {
  var type = type || this.type;
  var url = url || this.url;
  var callback = callback || this.callback;
  var data = data || this.data;
  // 创建XHR对象
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    // 监听状态
    if (xhr.readyState === 4) {
      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        // 解析JSON字符串给回调函数
        callback(JSON.parse(xhr.responseText));
      } else {
        console.log("error");
        return false;
      }
    }
  };
  // GET方法
  if (type.toUpperCase() === "GET") {
    if (typeof data === "object") {
      var data_send = "?";
      // 将data拼接到url中
      for (const key in data) {
        data_send += key + "=" + data[key];
        data_send += "&";
      }
      xhr.open(type, url + data_send, true);
      xhr.send(null);
    }
    // POST方法
  } else if (type.toUpperCase() === "POST") {
    xhr.open(type, url, true);
    // 说明Content-Type
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send(JSON.stringify(data));
  } else {
    console.log("error");
    return false;
  }
};

示例用法

var ajax = new Ajax({
  method: "get", //设置ajax方法
  url: "http://www.example.com",
  callback: function(res) {
    //设置回调函数
    alert(res);
  },
  data: data //需要传递的数据
});
ajax.send();

参考文献

  1. javascript 封装 ajax

  2. AJAX-MDN

  3. AJAX 维基百科,自由的百科全书

  4. 《JavaScript 高级程序设计》

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值