你的浏览器不支持canvas

Enjoy life!

Ajax - 上篇

Date: Author: JM

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。

今天主要总结一下自己对ajax(Asynchronous JavaScript XML)的一些看法。

show一张图

relationship-map

一、Ajax的灵魂 – XMLHttpRequest

  • XMLHttpRequest是整个Ajax技术的灵魂。可以说,没有XMLHttpRequest就没有Ajax
  • 下面讲一讲关于这个对象的浏览器兼容
    • ie7以下:有三个不同版本的XHR对象
      • MSXML2.XMLHttp
      • MSXML2.XMLHttp.3.0
      • MXSML2.XMLHttp.6.0
    • IE7+FirefoxOperaChromeSafari:支持原生的 XHR 对象
  • 完整版的createXHR()函数
function createXHR(){
     if (typeof XMLHttpRequest != "undefined"){
        return new XMLHttpRequest();
     } else if (typeof ActiveXObject != "undefined"){
         if (typeof arguments.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.");
     }
} 
  • 其实我们现在都不需要再兼容ie6、7那么低的版本了,因此可以直接按以下去创建xhr对象:
var xhr = new XMLHttpRequest();
  • 以下是输出的 xhr 对象

relation-map

二、xhr的用法

2.1 xhr.open()

xhr.open(method,url,isAsyn);
  • xhr.open()接受三个参数:
    1. method::要发送的请求的类型
      • postget
    2. url:请求的 URL
    3. isAsyn:表示是否异步发送请求的布尔值
      • true:异步
      • false:同步

xhr.open()不会真正发送请求,而只是启动一个请求以备发送。简单来说,就是起到一个打开连接的作用

在调用 open()之前指定 onreadystatechange事件处理程序才能确保跨浏览器兼容性。即:须在调用onreadystatechange事件后才能调用xhr.open()

2.2 xhr.send()

xhr.send(data|null);
  • xhr.send()只接受一个参数:要作为请求主体发送的数据。
    • 如果不需要通过请求主体发送数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。
  • 调用 send()之后,请求就会被分派到服务器

2.3 xhr.readyState属性

  • xhr.readyState:表示请求或者响应过程的当前活动阶段。
    • 0:未初始化。尚未调用 open()方法。
    • 1:启动。已经调用 open()方法,但尚未调用 send()方法。
    • 2:发送。已经调用 send()方法,但尚未接收到响应。
    • 3:接收。已经接收到部分响应数据。
    • 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。

2.4 xhr的readystatechange事件

  • xhr.readyState属性与readystatechange事件一起用。
    • 只要 readyState 属性的值由一个值变成另一个值,都会触发一次 readystatechange 事件。
    • 通常,我们只对readyState = 4有兴趣,因为此时所有数据已经接收完毕。
xhr.onreadystatechange = function() {
  if(xhr.readyState == 4 ) {
      //...
  }
};

2.5 xhr - 响应数据的相关属性

  • xhr - 响应数据的相关属性
    • responseText:作为响应主体被返回的文本。
    • responseXML:如果响应的内容类型是”text/xml“或”application/xml“,这个属性中将保存包含着响应数据的 XML DOM 文档。
    • status:响应的 HTTP 状态。
    • statusTextHTTP 状态的说明。
  • 在接收到响应后,即:readyState = 4后要做的事情:
    1. 检查 status 属性,以确定响应已经成功返回。
      • 200:响应成功
      • 304:表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本;当然,也意味着响应是有效的。
    2. 根据状态码做相应的事情
xhr.onreadystatechange = function() {
  if(xhr.readyState == 4 ) {
      if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
                alert(xhr.responseText);
      }
  }
};

2.6 xhr.abort()

  • xhr.abort(): 取消异步请求。
    • 调用这个方法后,XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。
    • 在终止请求之后,还应该对 XHR 对象进行解引用操作。由于内存原因,不建议重用 XHR 对象。
xhr.abort();

三、方法

3.1 get

  • get:向服务器查询某些信息。
  • 使用get方法时, 我们一般将查询字符串参数追加到 URL 的末尾,以便将信息发送给服务器。
    • 查询字符串中每个参数的名称和值都必须使用 encodeURIComponent()进行编码,然后才能放到 URL 的末尾;而且所有名-值对儿都必须由和号(&)分隔
xhr.open("get", "example.php?name1=value1&name2=value2", true); 
  • 辅助函数addUrlParams:向现有 URL 的末尾添加查询字符串参数
    • 接受三个参数
      • url:要添加参数的 URL
      • name:参数的值
      • value:参数的名称
function addUrlParams (url, name, value) {
    url += (url.indexOf("?") == -1 ? "?" : "&");
    
    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    
    return url;
}

var url = "example.php";
//添加参数
url = addURLParam(url, "name", "Nicholas");
url = addURLParam(url, "book", "Professional JavaScript");
//初始化请求
xhr.open("get", url, false); 
  1. 这个函数首先检查 URL 是否包含问号(以确定是否已经有参数存在)。
    • 如果没有,就添加一个问号。
    • 否则,就添加一个和号。
  2. 然后,将参数名称和值进行编码,再添加到 URL 的末尾。
  3. 最后返回添加参数之后的 URL。

3.2 post

  • post:用于向服务器发送应该被保存的数据。
    • post 方法会将数据作为请求的主体发送出去
    • post 请求的主体可以包含非常多的数据,而且格式不限

四、总结

其实使用Ajax很简单,就4步曲:

  1. 创建灵魂人物——xhr对象:var xhr = new XMLHttpRequest();
  2. 打开连接:xhr.open(...)
  3. 发送数据:xhr.send(...)
  4. 接收数据:xhr.onreadystatechange + xhr.readyState + xhr.status
    • 由于Ajax是异步的,所以onreadystatechange事件是放在xhr.open()之前的

接下来是封装好的ajax函数

  • es5
function ajax(config) {
    // 创建 xhr对象
     var xhr = new XMLHttpRequest(),
         headers = config.headers || [];
     
     // 接收数据
     xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
                        var data = JSON.parse(xhr.responseText);
                        config.fn && config.fn(data);
                    }
        }
     }
     // 打开连接
     xhr.open(config.method, config.url, config.isAsync || true);
     
     // 自定义请求头
     headers.forEach(function(item) {
        xhr.setRequestHeader(item.name, item.value);
     })
     
     // 发送数据
     xhr.send(config.data || null);
}
  • es6
const ajax = (config) => {
    const xhr = new XMLHttpRequest(),
          headers = config.headers || [];
    
    xhr.onreadystatechange = () => {
        if (xhr.readyState == 4) {
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
                const data = JSON.parse(xhr.responseText);
                config.fn && config.fn(data);
            }
        }
    }
    
     // 打开连接
     xhr.open(config.method, config.url, config.isAsync || true);
     
     // 自定义请求头
     headers.forEach(function(item) {
        xhr.setRequestHeader(item.name, item.value);
     })
     
     // 发送数据
     xhr.send(config.data || null);
}

对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。