天天看点

扒一扒 EventServiceProvider 源代码

Ajax

用一句话来说就是无须刷新页面即可从服务器取得数据。注意,虽然

Ajax

翻译过来叫异步

JavaScript

XML

,但是获得的数据不一定是

XML

数据,现在服务器端返回的都是

JSON

格式的文件。

完整的

Ajax

请求过程

Ajax

  1. 创建

    XMLHttpRequest

    实例
  2. 发出

    HTTP

    请求
  3. 接收服务器传回的数据
  4. 更新网页数据

下面先看一个红宝书上给出的发起

Ajax

请求的例子,

API

的用法在后面章节给出。

var xhr = new XMLHttpRequest();  // 创建XMLHttpRequest实例

xhr.onreadystatechange = function(){
  if (xhr.readyState == 4){   // 判断请求响应过程阶段,4 阶段代表已接收到数据
    if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {  // 校验HTTP状态码
      console.log(xhr.responseText);   // 输出响应的文本
    } else {
      console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
    }
  }
};

xhr.open('get', 'example.txt', true); // 初始化xhr实例,或者说启动请求
xhr.send(null);  // 设置HTTP请求携带参数,null为不带参数
           

Ajax

请求过程详解

1. 创建

XMLHttpRequest

从上面的的代码可以看出,创建一个

XHR

实例方式为:

var xhr = new XMLHttpRequest();
           

2. 发出HTTP请求

实例创建好后,首先需要启动一个

HTTP

请求,使用

XHR

open()

方法,

open

方法接受三个参数

XMLHttpRequest.open(method, url, isAsync)
// 例如
xhr.open('get', 'http://www.baidu.com', true)
           

第一个参数为

http

请求使用方法,如('get','post'等),第二是参数是请求的

url

, 第三个参数代表是否异步发送请求(可选)。调用

open()

方法后会启动一个

http

请求,但它不会立即发送请求,处于待命状态。需要注意的是:请求的

url

必须要跟请求源域(origin)同域,也就是说协议、域名、端口号要一致,跨域请求要使用别的方法。接着调用

send()

方法就会发出这个

http

请求。

xhr.open('get', 'http://www.baidu.com', true)
xhr.send(null)
           

send()

方法接受一个参数,为

http

请求发送的数据(通常用于'post'方法),如果为

null

,表示不发送数据。至此,一个异步的

http

请求就发送到了服务器。

3. 接收服务器传回的数据

3.1 发送同步请求

如果将

open

方法的第三个参数设为

false

,即为同步请求,当收到服务器的响应后,相应的数据会自动填充到

XHR

对象的属性中,主要包括以下四个:

  • responseText

    :作为响应主体被返回的文本。
  • responseXML

    : 响应返回的

    XML

    文档,能接收到的前提是,响应的

    Content-Type

    字段的值为

    text/xml

    或者

    application/xml

  • status

    :

    HTTP

    状态码。
  • statusText

    HTTP

    状态码说明。

当客户端收到以上信息后,首先要判断

HTTP

状态码来确认响应是否成功,状态码在200-300之间表示请求成功,同时304代表请求资源未被修改,可使用浏览器本地缓存。如果成功就可以获取响应报文主体中的数据了。

xhr.open('get', 'http://www.baidu.com', false)
xhr.send(null)

if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {  // 校验HTTP状态码
  console.log(xhr.responseText);   // 输出响应的文本
} else {
  console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
           

3.2 发送异步请求

open

true

,即为异步请求。那么就需要一个事件来通知程序异步请求的结果是否返回。

XHR

对象中的

readyState

属性,表示请求/响应整个过程所处的阶段,它有五个值分为对应五个阶段:

  • 0:未初始化。未调用

    open()

    方法。
  • 1:启动。已经调用

    open()

    方法,但未调用

    send()

  • 2:发送。已调用

    send()

    方法,但未收到响应。
  • 3: 接收。已经接收到部分响应数据。
  • 4:完成。已经接受到全部响应数据。

readyState

的值每变化一次,都会触发一次

readStatechange

事件,我们定义一个事件处理函数

onreadStatechange()

,并监听

readyState == 4

状态,就可以得知响应数据已全部收到,并进行下一步操作。那么就是文章开头给出的代码:

var xhr = new XMLHttpRequest();  // 创建XMLHttpRequest实例

xhr.onreadystatechange = function(){
  if (xhr.readyState == 4){   // 判断请求响应过程阶段,4 阶段代表已接收到数据
    if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {  // 校验HTTP状态码
      console.log(xhr.responseText);   // 输出响应的文本
    } else {
      console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
    }
  }
};

xhr.open('get', 'example.txt', true); // 初始化xhr实例,或者说启动请求
xhr.send(null);  // 设置HTTP请求携带参数,null为不带参数
           

补充XHR中三个有用的事件

timeout

事件

当超出了设置时间还未收到响应,就会触发

timeout

事件,进而调用

ontimeout

事件处理程序。同时

timeout

也是

XHR

的一个属性,用于设置这个时间阈值。下面是用法:

xhr.ontimeout = function() {
  alert('timeout!')
}

xhr.open('get', 'http://www.baidu.com', true)
xhr.timeout = 1000 // 时间阈值设为1秒
xhr.send(null)
           

load

load

事件用于简化对

readState

值的判断,响应数据全部接收完毕后(也就是

readState == 4

)会触发

load

事件,使用

onload

事件处理函数进行后续操作,

onload

会接收一个

event

对象,它的

target

属性等于

XHR

对象,当然我们在定义这个事件处理函数时也可以不传入这个参数,来看下面的用法:

var xhr = new XMLHttpRequest()
xhr.onload = function () {
  if(xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {
    console.log(xhr.responseText);   // 输出响应的文本
  } else {
    console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
  }
}
xhr.open('get', 'http://www.baidu.com', true)
xhr.send(null)
           

这样就不用去关心

readyState

值的变化情况了。当然如果想在特定

readyState

值上做一些逻辑处理,还是要用之前的方法。

progress

这个是很有用的一个事件,

progress

事件会在浏览器接收数据期间周期触发,代表整个请求过程的进度,它的事件处理程序

onprogress

接收一个

event

对象,

event.target

XHR

对象,另外

event

还有三个属性:

  • lengthComputable

    :Boolean值,进度信息是否可用。
  • position

    :已经接收到的字节数。
  • totalSize

    :总共要接收的字节数,被定义在响应报文的

    Content-Length

    字段中。

如果响应报文中有

Content-Length

字段,那么我们就可以计算当前时刻响应数据的加载进度了,这也是之前看到的一个面试题。看下面的代码:

xhr.onprogress = function(event) {
  if(event.lengthComputable) {
    console.log(`Received: ${(event.position/event.totalSize).toFixed(4)*100}%`);
  }
}
           

其他还有很多有用的API,如

FormData

表单序列化,

overrideMimeType()

重写

XHR

响应的

MIME

类型等等,后面慢慢更新。

原文地址:https://segmentfault.com/a/1190000015668383

继续阅读