JavaScript XHR的用法和自定义封装

  2005年Jesse James Garrett发表了一篇在线文章,题为 "Ajax: A new Approach to Web Applications" 。他在这篇文章里介绍了一种技术,用他的话说,就叫 Ajax ,是对 Asynchronous JavaScript + XML 的简写。这一种技术,能够向服务器请求额外的数据而无须卸载页面,会带来更好的用户体验。Carrett 还解释了怎样使用这一技术改变自从Web诞生以来就一直沿用的“单机,等待”的交互模式。Ajax技术的核心是 XMLHttpRequest 对象(简称XHR)

  IE7之前的版本,创建XHR对象只能通过下面的方法:

function createXHR () {
    if (typeof agreement.callee.activeXString != 'string' ) {
        var versions = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP"],
        i, len;
        for (i = 0, len = versions.length; i < len; i++) {
            try (
                new ActiveXObject(versions[i]);
                arguments.callee.activeXString = versions[i];
                break;
            } catch (ex) {
                // 跳过
            }
        }
    }
    return new ActiveXObject(arguments.callee.activeXString);
}

  IE7+、 FireFox、Opera、Chrome 和 Safari 都支持原生的 XHR 对象,在这些浏览器中创建 XHR 对象要像下面这样使用 XMLHttpRequest 构造函数。

var xhr = new XMLHttpRequest();

  综合以上的情况,既支持IE的早期版本也支持IE7以及更高版本的浏览器,就可以这样做:

function createXHR () {
    if (typeof XMLHttpRequest != 'undefined') {
        return new XMLHttpRequest()
    } else if (typeof ActiveXObject != 'undefined') {
      if (typeof agreement.callee.activeXString != 'string' ) {
          var versions = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP"],
          i, len;
          for (i = 0, len = versions.length; i < len; i++) {
              try (
                  new ActiveXObject(versions[i]);
                  arguments.callee.activeXString = versions[i];
                  break;
              } catch (ex) {
                  // 跳过
              }
          }
      }
      return new ActiveXObject(arguments.callee.activeXString);
  } else {
    throw new Error('No XHR object available.');  
  }
}

  由于其他浏览器中对XHR的实现与IE最早的实现是兼容的,因此就可以在所有浏览器中都以相同方式使用这个方法创建 xhr 对象:

var xhr = new createXHR();

  在创建了 xhr 对象之后,可以调用该对象上的 open() 方法,创建一个请求。此方法有三个参数:请求类型,请求路径,是否异步发送请求(默认为true);

  再调用该对象的 send() 方法,发送请求。如果是 post 请求则需要传入请求参数。如:xhr.send('a=4&b=0');

  请求发送成功后,再通过监测状态来获取:onreadystatechange;在这个方法中监听 xhr 的 readyState 和 status ;

  对 xhr 的封装类似JQuery的get、post、ajax 方法。ajax方法可以是get或者post,该方法可以传入多个参数,返回一个Promise对象。

var $ = {
    createXHR: function () {
      if (typeof XMLHttpRequest != 'undefined') {
          return new XMLHttpRequest()
      } else if (typeof ActiveXObject != 'undefined') {
        if (typeof agreement.callee.activeXString != 'string' ) {
            var versions = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP"],
            i, len;
            for (i = 0, len = versions.length; i < len; i++) {
                try (
                    new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    break;
                } catch (ex) {
                    // 跳过
                }
            }
        }
        return new ActiveXObject(arguments.callee.activeXString);
    } else {
      throw new Error('No XHR object available.');  
    }
  },
   get: function(url, data, callback, dataType) {
     // 避免dataType大小写的问题 let dataType = dataType.toLowerCase() // 如果有传入data,则在url后面跟上参数 if(data) { url += '?' Object.keys(data).forEach(key => url += `${key}=${data[key]}&`)     url = url.slice(0, -1)     } // 调用我们封装的方法生成XHR对象 let xhr = this.createXHR() // 创建get请求 xhr.open('get', url) // 发送请求 xhr.send() xhr.onreadystatechange = function() { if(xhr.readyState === 4) { if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { // 若dataType为json,则将返回的数据通过JSON.parse格式化 let res = dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText // 调用回调函数,并把参数传进去 callback(res, xhr.status, xhr) } } } }, post: function(url, data, callback, dataType) { // 避免dataType大小写的问题 let dataType = dataType.toLowerCase() // 调用我们封装的方法动态生成XHR对象 let xhr = this.createXHR() let str = '' // 若传入参数,则将参数序列化 if(data) { Object.keys(data).forEach(key => str += `${key}=${data[key]}&`) str = str.slice(0, -1) } // 设置头部信息 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') // 发送请求,并携带参数 xhr.send(str) xhr.onreadystatechange = function() { if(xhr.readyState === 4) { if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { // 若dataType为json,则将返回的数据通过JSON.parse格式化 let res = dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText // 调用回调函数,把对应参数传进去 callback(res, xhr.status, xhr) } } } }, ajax: function(params) { // 初始化参数 let type = params.type ? params.type.toLowerCase() : 'get' let isAsync = params.isAsync ? params.isAsync : 'true' let url = params.url let data = params.data ? params.data : {} let dataType = params.dataType.toLowerCase() // 用我们封装的方法动态生成XHR对象 let xhr = this.createXHR() let str = '' // 拼接字符串 Object.keys(data).forEach(key => str += `${key}=${data[key]}&`) str = str.slice(0, -1) // 如果是get请求就把携带参数拼接到url后面 if(type === 'get') url += `?${str}`; // 返回promise对象,便于外部then和catch函数调用 return new Promise((resolve, reject) => { // 创建请求 xhr.open(type, url, isAsync) if(type === 'post') { xhr.setRequestHeader('Content-Type', 'application/x-www-form-rulencoded') xhr.send(str) } else { xhr.send() } xhr.onreadystatechange = function() { if(xhr.readyState === 4) { if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { let res = dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText resolve(res) // 请求成功,返回数据 } else { reject(xhr.status) // 请求失败,返回状态码 } } } }) } }
}
原文地址:https://www.cnblogs.com/matthewkuo24/p/14075006.html