现在流行的 Ajax 库,都是基于 Promise 实现的,如:axios。所以基于 Promise 封装一个简单的 Ajax 库,来理解其原理。
参数设置
options: [Object]
type: [String] 请求方式,默认 get
url: [String] 请求地址
data: [Object] 发送的数据
dataType: [String] 数据类型,json/xml/text,默认 json
cache: [Boolean] 是否缓存,默认不缓存
默认都是异步操作,不支持同步
整体结构
使用一个闭包封装,然后通过挂载到 window 来使用,借用了 JQuery 的思想
;(function(window) {function ajaxPromise(options) {//...}window.ajax = ajaxPromise;})(window)
构造函数
由于这个方法基于 Promise 来管理 Ajax 操作,所以,构造函数必定返回一个 Promise 实例。
在这个 Promise 实例中的回调函数中执行 Ajax 操作,把参数的处理,放到外面。
function ajaxPromise(opts) {//=> 处理各种参数return new Promise(function (resolve, reject) {//=> 这里执行原生 Ajaxlet xhr = new XMLHttpRequest();xhr.open(type, url); // 默认异步xhr.onreadystatechange = function () {if (xhr.readyState === 4 && /^2\d{2}|304/.test(xhr.status)) {//=> 成功// 处理数据类型//...resolve(data);}if (xhr.readyState === 4 && /^[45]\d{2}/.test(xhr.status)) {//=> 失败reject(xhr);}};//=> 设置请求头,使得后台接受的参数是 form data,而不是字符串xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=utf-8');xhr.send(data);})}
参数的处理与前面封装的 Ajax 库一样,这里不再赘述。
这里只需要简单的在 Ajax 请求成功后,执行 resolve,失败后执行 reject 即可。
代码
; (function (window) {function ajaxPromise(opts) {let {url,type = 'get',data = {},dataType = 'json',cache = false} = opts;//=> 处理 dataif (typeof data === 'object') {let str = '';for (let k in data) {if (data.hasOwnProperty(k)) {str += `${k}=${data[k]}&`;}}data = str.slice(0, str.length - 1);}// 判断是否是 get 类型请求if (/^(GET|DELETE|HEAD|TRACE|OPTIONS)$/i.test(type)) {let char = '';if (url.indexOf('?') === -1) {char = `?`;} else {url = url.replace(/&$/, '');char = `&`;}url += `${char}${data}`;data = null;}//=> 处理 cacheif (/^GET$/i.test(type) && cache === false) {//=> url 末尾追加时间戳let char = '';if (url.indexOf('?') === -1) {char = `?`;} else {url = url.replace(/&$/, '');char = `&`;}url += `${char}_=${+(new Date())}`;this.url = url;}return new Promise(function (resolve, reject) {//=> 这里执行原生 Ajaxlet xhr = new XMLHttpRequest();xhr.open(type, url); // 默认异步xhr.onreadystatechange = function () {if (xhr.readyState === 4 && /^2\d{2}|304/.test(xhr.status)) {//=> 成功// 处理数据类型let data = xhr.responseText;switch (dataType.toLowerCase()) {case 'json':data = JSON.parse(data);break;case 'xml':data = xhr.responseXML;case 'text':break;default:}resolve(data);}if (xhr.readyState === 4 && /^[45]\d{2}/.test(xhr.status)) {//=> 失败reject(xhr);}};//=> 设置请求头,使得后台接受的参数是 form data,而不是字符串xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=utf-8');xhr.send(data);})}window.ajaxPromise = ajaxPromise;}) (window);
