JavaScript 系列 - Ajax、Fetch、服务器发送事件

75 阅读5分钟

Ajax

概念

Asynchronous JavaScript And XML

本身不是一种技术,而是一种将一些现有技术结合起来使用的方法,包括:HTML 或 XHTML、CSS、JavaScript、DOM、XML、XSLT、以及最重要的 XMLHttpRequest 对象。

网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。这使得程序能够更快地回应用户的操作。

XMLHttpRequest

构造函数

XMLHttpRequest()

该构造函数用于初始化一个 XMLHttpRequest 实例对象。在调用下列任何其他方法之前,必须先调用该构造函数,或通过其他方式,得到一个实例对象。

属性

状态

  • XMLHttpRequest.onreadystatechange readyState 属性回调函数

  • XMLHttpRequest.readyState

    只读,代表请求的状态码

    状态描述
    0UNSENT代理被创建,但尚未调用 open() 方法。
    1OPENEDopen() 方法已经被调用。
    2HEADERS_RECEIVEDsend() 方法已经被调用,并且头部和状态已经可获得。
    3LOADING下载中;responseText 属性已经包含部分数据。
    4DONE下载操作已完成。
  • XMLHttpRequest.status 标准的 HTTP status codes(只读)

  • XMLHttpRequest.statusText 标准的状态文本信息

response

  • XMLHttpRequest.response 响应实体(只读)
  • XMLHttpRequest.responseText 响应文本(只读)
  • XMLHttpRequest.responseType 响应类型
    • "" 文本
    • "arraybuffer" 二进制数据 ArrayBuffer
    • "blob" 二进制数据 Blob 对象
    • "document" HTML
    • "json"
    • "text" 文本
  • XMLHttpRequest.responseURL 响应文本 URL 序列化(只读)
  • XMLHttpRequest.responseXML 响应 XML(只读)

设置

  • XMLHttpRequest.timeout 超时
  • XMLHttpRequest.upload 代表上传进度
  • XMLHttpRequest.withCredentials 是否应当带有授权信息,如 cookie 或授权 header 头

实例方法

  • XMLHttpRequest.abort() 中止请求
  • XMLHttpRequest.getAllResponseHeaders() 获取所有响应头信息,字符串 和 null
  • XMLHttpRequest.getResponseHeader(name) 获取指定响应头信息,字符串 和 null
  • XMLHttpRequest.open(method, url, async, user, password) 初始化一个请求
  • XMLHttpRequest.overrideMimeType(mimeType) 覆写 MIME 类型
  • XMLHttpRequest.send(body) 发送请求默认异步
  • XMLHttpRequest.setRequestHeader(header, value) open() 之后、send() 之前调用

事件

  • abort
  • error
  • load 请求成功完成时触发
  • loadend 请求成功还是失败
  • loadstart 接收到响应数据时触发
  • progress
  • timeout
// 创建一个 promise 对象
let promise = new Promise(function (resolve, reject) {
  let xhr = new XMLHttpRequest();
  // 新建一个 http 请求
  xhr.open("GET", url, true);
  // 设置状态的监听函数
  xhr.onreadystatechange = function () {
    if (this.readyState !== 4) return;
    // 当请求成功或失败时,改变 promise 的状态
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      resolve(this.response);
      // var blob = new Blob([xhr.response], { type: "image/jpeg" });
    } else {
      reject(new Error(this.statusText));
    }
  };
  // 设置错误监听函数
  xhr.onerror = function () {
    reject(new Error(this.statusText));
  };
  // 设置响应的数据类型
  xhr.responseType = "json";
  // 设置请求头信息
  xhr.setRequestHeader("Accept", "application/json");
  // 发送 http 请求
  xhr.send(null);
});
// form
var formData = new FormData(form);
formData.append("csrf", "e69a18d7db1286040586e6da1950128c");
xhr.send(formData);
// upload
function upload(blobOrFile) {
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "/server", true);
  xhr.onload = function (e) {};
  var progressBar = document.querySelector("progress");
  xhr.upload.onprogress = function (e) {
    if (e.lengthComputable) {
      progressBar.value = (e.loaded / e.total) * 100;
      // 兼容不支持 <progress> 元素的老式浏览器
      // progressBar.textContent = progressBar.value;
    }
  };
  xhr.send(blobOrFile);
}
upload(new Blob(["hello world"], { type: "text/plain" }));

Fetch

Fetch API 提供了一个获取资源的接口(包括跨网络通信)

fetch(input[, init])

  • input

    URL 字符串或者 Request 对象

  • init

    一个配置项对象,包括所有对请求的设置。可选的参数有:

    • method: 请求使用的方法
    • headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量
    • body: 请求的 body 信息,GET 或 HEAD 方法的请求不能包含 body 信息
    • mode: 请求的模式
      • cors
      • no-cors
      • same-origin
    • credentials: 请求的 credentials
      • omit
      • same-origin
      • include
      • 为了在当前域名内自动发送 cookie,必须提供这个选项
    • cache: 请求的 cache 模式
      • default
      • no-store
      • reload
      • no-cache
      • force-cache
      • only-if-cached
    • redirect: 可用的 redirect 模式
      • follow (自动重定向) 默认
      • error (如果产生重定向将自动终止并且抛出一个错误)
      • manual (手动处理重定向) Chrome 47 之前默认
    • referrer
      • no-referrer
      • client 默认
      • URL
    • referrerPolicy: 指定了 HTTP 头部 referer 字段的值。
      • no-referrer
      • no-referrer-when-downgrade
      • origin
      • origin-when-cross-origin
      • unsafe-url
    • integrity: 包括请求的 subresource integrity 值

Headers

允许您对 HTTP 请求和响应头执行各种操作。

  • Headers.Headers(init)
  • Headers.append(name, value)
  • Headers.delete(name)
  • Headers.entries()
  • Headers.get(name)
  • Headers.has(name)
  • Headers.keys()
  • Headers.set(name, value)
  • Headers.values()
// html
fetch("./AJAX.html")
  .then((res) => {
    return res.text();
  })
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {});
// json
fetch("./data.json")
  .then((res) => {
    return res.json();
  })
  .then((json) => {
    console.log(json);
  })
  .catch((err) => {});
// Form
var form = document.querySelector("#registration");
function postForm() {
  fetch(`/api/user/${name}`, {
    method: "POST",
    body: new FormData(form),
  });
  return false;
}
// POST
fetch("/api", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "CaiCai",
    age: "26",
  }),
});
// 中止
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 5000);

fetch("/api/user/CaiCai", {
  signal, // 在option中加入signal
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "CaiCai",
    age: "26",
  }),
})
  .then((res) => {
    return res.json();
  })
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {
    console.log(err);
  });

Request

构造函数

  • Request(input[, init])

    创建一个新的 Request 对象

实例属性

  • Request.body
  • Request.bodyUsed 请求是否仍然未被使用
  • Request.cache 包含请求的缓存模式
  • Request.credentials 默认是 same-origin
  • Request.destination 请求的内容类型。
  • Request.headers
  • Request.integrity 包含请求的子资源完整性值
  • Request.method
  • Request.mode 包含请求的模式
  • Request.redirect 包含如何处理重定向的模式
  • Request.referrer 包含请求的 referrer
  • Request.referrerPolicy 包含请求的 referrer 策略
  • Request.signal 返回与请求相关联的 AbortSignal
  • Request.url

实例方法

  • Request.arrayBuffer() 返回 promise
  • Request.blob() 返回 promise
  • Request.clone() 创建一个当前 Request 对象的副本
  • Request.formData() 返回 promise
  • Request.json() 返回 promise
  • Request.text() 返回 promise

Response

构造函数

  • Response(body, init)

属性

  • Response.headers
  • Response.ok 布尔值,HTTP 状态码的范围在 200-299
  • Response.redirected 表示该 Response 是否来自一个重定向
  • Response.status
  • Response.statusText
  • Response.type
  • Response.url
  • Response.useFinalURL 布尔值,是否是该 Response 的最终 URL
  • Response.body
  • Response.bodyUsed 该 Response 是否读取过 Body

方法

  • Response.clone()
  • Response.error()
  • Response.redirect(url, status)
  • Body.arrayBuffer()
  • Body.blob()
  • Body.formData()
  • Body.json()
  • Body.text()
var myImage = document.querySelector("img");
var myRequest = new Request("flowers.jpg");
var myHeaders = new Headers();
myHeaders.append("Content-Type", "image/jpeg");
var myInit = {
  method: "GET",
  headers: myHeaders,
  mode: "cors",
  cache: "default",
};
fetch(myRequest, myInit)
  .then(function (response) {
    return response.blob();
  })
  .then(function (response) {
    var objectURL = URL.createObjectURL(response);
    myImage.src = objectURL;
  });

服务器发送事件

使用服务器发送事件,服务器可以随时向我们的 Web 页面推送数据和信息。

EventSource

EventSource 接口是 web 内容与服务器发送事件通信的接口。

一个 EventSource 实例会对 HTTP 服务器开启一个持久化的连接,以 text/event-stream 格式发送事件,此连接会一直保持开启直到通过调用 EventSource.close() 关闭。

一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个 event 字段,触发的事件与 event 字段的值相同。如果不存在 event 字段,则将触发通用的 message 事件。

构造函数

EventSource(url, configuration)

withCredentials,默认为 false,指示 CORS 是否应包含凭据 (credentials)

创建一个新的 EventSource,用于从指定的 URL 接收服务器发送事件,可以选择开启凭据模式。

实例属性

  • EventSource.readyState

    代表连接状态

    • CONNECTING(0)
    • OPEN(1)
    • CLOSED(2)
  • EventSource.url

  • EventSource.withCredentials

实例方法

  • EventSource.close()

    关闭连接并将 readyState 属性设置为 CLOSED

事件

error、message、open 此外,事件源本身可以发送具有 event 字段的消息,这将创建一个以该值为键的特定事件。

const button = document.querySelector("button");
const evtSource = new EventSource("sse.php");
console.log(evtSource.withCredentials);
console.log(evtSource.readyState);
console.log(evtSource.url);
const eventList = document.querySelector("ul");
evtSource.onopen = function () {
  console.log("Connection to server opened.");
};
evtSource.onmessage = function (e) {
  const newElement = document.createElement("li");
  newElement.textContent = "message: " + e.data;
  eventList.appendChild(newElement);
};
evtSource.onerror = function () {
  console.log("EventSource failed.");
};
button.onclick = function () {
  console.log("Connection closed");
  evtSource.close();
};
// evtSource.addEventListener("ping", function(e) {
//   var newElement = document.createElement("li");
//
//   var obj = JSON.parse(e.data);
//   newElement.innerHTML = "ping at " + obj.time;
//   eventList.appendChild(newElement);
// }, false);