基础系列-ajax与fetch

AJAX

概念

Asynchronous JavaScript + XML(异步JavaScript和XML), 其本身不是一种新技术,而是一个在 2005年被Jesse James Garrett提出的新术语,用来描述一种使用现有技术集合的‘新’方法,包括: HTMLXHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要的 XMLHttpRequest。当使用结合了这些技术的AJAX模型以后, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。这使得程序能够更快地回应用户的操作。

请求的数据格式

设置 Content-Type 实体头部用于指示资源的MIME类型

text/html:请求 Web ⻚面时返回响应的类型,Body 中返回 html 文本。

application/json:常用,复杂的数据结构。

multipart/form-data:提交文件、非 ASCII 码的数据或者是二进制流数据。

application/x-www-form-urlencoded:form表单默认编码方式。

XMLHttpRequest

概念

XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequestAJAX 编程中被大量使用。

XMLHttpRequest 可以用于获取任何类型的数据,而不仅仅是 XML。它甚至支持 HTTP 以外的协议(包括 file:// 和 FTP),尽管可能受到更多出于安全等原因的限制。

属性和方法

属性
  • upload:(只读)上传进度。
  • status:(只读)代表请求响应状态。返回一个无符号短整型数字。
  • readyState:(只读)代表请求的状态码。
    • 0 - UNSENT - 代理被创建,但尚未调用 open() 方法
    • 1 - OPENED - open() 方法已经被调用
    • 2 - HEADERS_RECEIVED - send() 方法已经被调用,并且头部和状态已经可获得
    • 3 - LOADING - 下载中;responseText 属性已经包含部分数据
    • 4 - DONE - 下载操作已完成
  • response:(只读)包含整个响应实体。返回一个 ArrayBufferBlobDocument,或 DOMString,具体是哪种类型取决于 XMLHttpRequest.responseType 的值。
  • responseText:(只读)返回一个 DOMString,该 DOMString 包含对请求的响应,如果请求未成功或尚未发送,则返回 null
  • responseType:一个用于定义响应类型的枚举值。
  • responseURL:(只读)返回经过序列化(serialized)的响应 URL,如果该 URL 为空,则返回空字符串。
  • responseXML:(只读)返回一个 Document,其中包含该请求的响应,如果请求未成功、尚未发送或时不能被解析为 XML 或 HTML,则返回 null
  • statusText:(只读)返回一个 DOMString,其中包含 HTTP 服务器返回的响应状态。与 XMLHTTPRequest.status 不同的是,它包含完整的响应状态文本(例如,”200 OK“)。
  • timeout:超时时长。
  • ontimeout:设置一个函数处理超时问题。
  • withCredentials:一个布尔值,用来指定跨域 Access-Control 请求是否应当带有授权信息,如 cookie 或授权 header 头。
方法
  • .abort():如果请求已被发出,则立刻中止请求。
  • .getAllResponseHeaders():以字符串的形式返回所有用 CRLF 分隔的响应头,如果没有收到响应,则返回 null
  • .getResponseHeader():返回包含指定响应头的字符串,如果响应尚未收到或响应中不存在该报头,则返回 null
  • .open():初始化一个请求。
  • .overrideMimeType():覆写由服务器返回的 MIME 类型。
  • .send():发送请求。如果请求是异步的(默认),那么该方法将在请求发送后立即返回。
  • .setRequestHeader():设置 HTTP 请求头的值。必须在 open() 之后、send() 之前调用 setRequestHeader() 方法。
事件

使用 xhr.addEventListener 的方式添加监听事件,或使用on-*属性进行设置监听

  • abort:可以设置监听 abort() 方法调用。

  • error:错误时触发。

  • progress:当请求接受到更多数据时,周期性地触发。

  • load:请求成功完成时触发。

  • loadend:当请求结束时触发,无论成功还是失败。

  • loadstart:接受到响应数据时触发。

  • timeout:在预设时间内没有接受到响应时触发。

实战

function request(data === null) {
    if (!data) {
        return
    }
    const xhr = new XMLHttpRequest()
    xhr.onreadystatechange = function() {
        // 请求操作已完成
        if (xhr.readyState == 4)) {
            // 判断响应状态
            if (xhr.status.toString().startsWith('2') || xhr.status === 304) {
                // 获取返回结果
                const res = xhr.response
                console.log(res)
            } else {
              console.error('error: ', xhr.status)
            }
        }
    }
    // 初始化一个请求,第三个参数设置异步请求还是同步请求,默认值为false为异步请求
    xhr.open('GET', 'url.action')
    // 出错时处理
    xhr.onerror = function () {
      	console.log("An error occurred during the transaction");
    };
    // 必须在 open 之后,send之前设置 header
    xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
    // 设置超时
    xhr.timeout = 10000 // 设置 10 秒超时
    xhr.ontimeout = function() {
        console.log("Request did not return in a second.")
    }
    // 发送请求
    xhr.send(data) 
} 

promise 改造

function request(formData = null) {
  if (!formData) {
      return
  }
  return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      xhr.onreadystatechange = function() {
          // 请求操作已完成
          if (xhr.readyState === 4) {
              // 判断响应状态
              if (xhr.status.toString().startsWith('2') || xhr.status === 304) {
                  // 获取返回结果
                  const res = xhr.response
                  resolve(res)
              } else {
                  reject(xhr.status)
              }
          }
      }
      // 初始化一个请求,第三个参数设置异步请求还是同步请求,默认值为false为异步请求
      xhr.open(formData.method, formData.url)
      // 必须在 open 之后,send之前设置 header
      xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
      // 设置超时
      xhr.timeout = 10000 // 设置 10 秒超时
      xhr.ontimeout = function() {
          console.log("Request did not return in a second.")
      }
      // 发送请求
      xhr.send(formData.data || null)
  })
}

// 使用
request({
  method: 'GET',
  url: 'www.baidu.com',
  data: null,
}).then(res => console.log(res)).catch(err => console.error(err))

Fetch

相对于 XMLHttpRequest 相同的功能,但更具有可扩展性和高效性。

Fetch API 提供了一个获取资源的接口(包括跨域请求)。且基于 Promise。

核心

Fetch 的核心在于对 HTTP 接口的抽象,包括 RequestResponseHeadersBody,以及用于初始化异步请求的 global fetch。得益于 JavaScript 实现的这些抽象好的 HTTP 模块,其他接口能够很方便的使用这些功能。

Guard

Guard 是 Headers 对象的特性,基于不同的情况,它可以有以下取值:immutablerequestrequest-no-corsresponsenone

头信息的 guard 会影响 set()delete()append() 方法。

实战

var myImage = document.querySelector('img');

var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg');

fetch(myRequest,myInit).then(function(response) {
  ...
});
    
// 或
var myInit = { method: 'GET',
               headers: {
                   'Content-Type': 'image/jpeg'
               },
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg', myInit);