共计 4332 个字符,预计需要花费 11 分钟才能阅读完成。
什么是 AJAX?
AJAX 是异步的 JavaScript 和 XML(Asynchronous JavaScript And XML)。简略点说,就是应用 XMLHttpRequest 对象与服务器通信。它能够应用 JSON,XML,HTML 和 text 文本等格局发送和接收数据。AJAX 最吸引人的就是它的“异步”个性,也就是说它能够在不从新刷新页面的状况下与服务器通信,替换数据,或更新页面。
通过交互式网站和古代 Web 规范,AJAX 正在逐步被 JavaScript 框架中的函数和官网的 Fetch API 规范取代。
XMLHTTPRequest
XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 能够在不刷新页面的状况下申请特定 URL,获取数据。这容许网页在不影响用户操作的状况下,更新页面的部分内容。XMLHttpRequest 在 AJAX 编程中被大量应用。
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');
// request state change event
xhr.onreadystatechange = function () {
// request completed?
if (xhr.readyState !== 4) return;
if (xhr.status === 200) {
// request successful - show response
console.log(xhr.responseText);
} else {
// request error
console.log('HTTP error', xhr.status, xhr.statusText);
}
};
// xhr.timeout = 3000; // 3 seconds
// xhr.ontimeout = () => console.log('timeout', xhr.responseURL);
// progress 事件能够报告长时间运行的文件上传
// xhr.upload.onprogress = p => {// console.log(Math.round((p.loaded / p.total) * 100) + '%');
// }
// start request
xhr.send();
全副 readyState 状态值都在 XMLHTTPRequest.readyState,如下也是:
- 0 UNSENT Client has been created. open() not called yet.
- 1 OPENED open() has been called.
- 2 HEADERS_RECEIVED send() has been called, and headers and status are available.(服务器已收到申请)
- 3 LOADING Downloading; responseText holds partial data.(服务器正在解决申请)
- 4 DONE The operation is complete.
Fetch API
语法
Promise<Response> fetch(url[, option]);
参数
url
:URL 字符串或者一个 Request 对象-
option
可选,一个配置项对象method
: 申请应用的办法,如 GET、POST。headers
:申请头信息body
:申请的 body 信息mode
: 申请的模式,如 cors、no-cors 或者 same-origin。credentials
: 申请的 credentials,如 omit、same-origin 或者 include。为了在以后域名内主动发送 cookie,必须提供这个选项。因为 默认是不携带 cookie 的。cache
: 申请的 cache 模式: default、no-store、reload、no-cache、force-cache 或者 only-if-cached。signal
:一个 AbortSignal 对象实例,容许您与 fetch 申请进行通信,并在须要时通过 AbortController 停止它。
应用示例
-
HTTP 谬误(例如 404 Page Not Found 或 500 Internal Server Error)不会导致 Fetch 返回的 Promise 标记为 reject,从而 catch 办法也不会被执行。想要准确的判断 fetch 是否胜利,须要蕴含 promise resolved 的状况,此时再判断 response.ok 是不是为 true
fetch('http://domain/service', {method: 'GET'}) .then(response => {if (response.ok) {return response.json(); } throw new Error('Network response was not ok.'); }) .then(json => console.log(json)) .catch(error => console.error('error:', error));
-
fetch 不反对设置超时,须要应用 promise
function fetchTimeout(url, init, timeout = 3000) {return new Promise((resolve, reject) => {fetch(url, init) .then(resolve) .catch(reject); setTimeout(reject, timeout); }) }
-
终止 fetch
const controller = new AbortController(); fetch( 'http://domain/service', { method: 'GET', signal: controller.signal }) .then(response => response.json()) .then(json => console.log(json)) .catch(error => console.error('Error:', error)); controller.abort();
留神:
xhr 的回调是宏工作,fetch 基于 promise 实现,其回调是微工作
常见 HTTP 申请头 / 响应头 / 状态码
request header
- :method: GET
- :path:
- :scheme: https
- accept: application/json, text/plain, /
- accept-encoding: gzip, deflate, br
- cache-control: no-cache
- cookie: deviceId=c12;
- origin:
- referer:
- user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
response header
- access-control-allow-credentials: true
- access-control-allow-origin:
- content-encoding: gzip
- content-type: application/json;charset=UTF-8
- date: Thu, 06 Aug 2020 08:15:05 GMT
- set-cookie: sess=QvrAQ0Cq+EcDQQPTer2X;
- status: 200
status
- 200 get 胜利
- 201 post 胜利
- 301 永恒重定向
- 302 长期重定向
- 304 协商缓存 服务器文件未修改
- 400 客户端申请有语法错误,不能被服务器辨认
- 403 服务器受到申请,然而回绝提供服务,可能是跨域
- 404 申请的资源不存在
- 405 申请的 method 不容许
- 500 服务器产生不可预期的谬误
封装一个跨浏览器兼容的申请函数
interface IOptions {
url: string;
type?: "GET" | "POST";
data: any;
timeout?: number;
}
function formatUrl(object) {
// a=xxx&b=xxxx; querystring
let dataArr = [];
for (let key in object) {dataArr.push(`${key}=${encodeURIComponent(object[key])}`);
}
return dataArr.join("&");
}
export function ajax(
options: IOptions = {
type: "GET",
data: {},
timeout: 3000,
url: "",
}
) {return new Promise((resolve, reject) => {if (!options.url) {return;}
const queryString = formatUrl(options.data);
const onStateChange = () => {xhr.onreadystatechange = () => {if (xhr.readyState === 4) {clearTimeout(timer);
if ((xhr.status >= 200 && xhr.status < 300) ||
xhr.status === 304
) {resolve(xhr.responseText);
} else {reject(xhr.status);
}
}
};
};
let timer;
let xhr;
if ((window as any).XMLHttpRequest) {xhr = new XMLHttpRequest();
} else {xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
if (options.type.toUpperCase() === "GET") {xhr.open("GET", `${options.url}?${queryString}`);
onStateChange();
xhr.send();} else if (options.type.toUpperCase() === "POST") {xhr.open("POST", options.url);
xhr.setRequestHeader(
"ContentType",
"application/x-www-form-urlencoded"
);
onStateChange();
xhr.send(options.data);
}
if (options.timeout) {timer = setTimeout(() => {xhr.abort();
reject("timeout");
}, options.timeout);
}
});
}