ajax就是异步的JavaScript和XML
ajax也就是我们客户端给服务端发送请求以及接受响应的工具
ajax四部曲
- 创建ajax实例对象 (XMLHttpRequest)
- 连接服务器(open方法)
- 发送请求(send方法)
- 接受服务器响(onreadystatechange/onload)
ajax的状态:
- 0 未初始化
- 1 open方法执行完成
- 2 send方法执行完成
- 3 正在解析响应内容
- 4 交互完成,解析完成
http状态码
- 1**:消息
- 2**:成功
- 3**:重定向(304使用缓存)
- 4**:客户端错误(403权限不够/404参数错误)
- 5**:服务器端错误(503过载)
原生js封装Ajax
插件封装都是基于对象做参数,因为对象是无序的,免去参数顺序带来记忆问题
open的三个参数都是可能改变的
get和post提交数据方式不统一的,不一定每次都提交数据
获取接口数据进行渲染
function ajax(options) { //options:配置参数,配置参数可以配置默认值。
// 判断请求方式
options.type = options.type || 'get'; //如果传入option.type就使用,否则使用默认的get
// 接口地址
if (!options.url) {
throw new Error('接口地址必须存在'); //抛出错误 new Error生成错误对象,抛出错误。
}
// 是否异步
if (options.async === 'false' || options.async === false) { //同步
options.async = false;
} else {
options.async = true;
}
// 判断数据
if (options.data && Object.prototype.toString.call(options.data) === '[object Object]') { //数据存在,同时是对象格式
let arr = [];
for (let key in options.data) {
arr.push(key + '=' + options.data[key]);
}
options.data = arr.join('&');
}
// 数据存在,同时数据可以是get和post方式进行发送
// get方式
if (options.data && options.type === 'get') {
options.url += '?' + options.data;
}
let xhr = new XMLHttpRequest();
xhr.open(options.type, options.url, options.async);
// post方式
if (options.data && options.type === 'post') {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
xhr.send(options.data);
} else {
xhr.send();
}
// 获取接口数据
xhr.onload = function() { //异步数据
if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) { //请求完成,接口地址正确
options.success(xhr.responseText)
} else {
options.error('接口地址有误');
}
}
}
ajax({
type: 'get', //请求方式
url: 'abc', //接口地址,必须存在
data: { //数据
a: 1,
b: 2,
c: 3
},
async: 'true', //是否异步
success: function(res) { //成功获取数据的方法
console.log(res);
},
error: function(err) { //接口失败的方法
throw new Error(err)
}
});
Promise
异步编程的一种解决方案,解决异步回调地狱问题
异步编程:定时器、fs文件操作、AJAX、数据库操作等
语法:
new Promise(function (resolve, reject) {
// resolve 表示成功的回调
// reject 表示失败的回调
}).then(function (res) {
// 成功的函数
}).catch(function (err) {
// 失败的函数
})
三种状态: pending(等待态),fulfilled(成功态),rejected(失败态);状态一旦改变,就不会再变。
promise的静态方法:
- Promise.all
- Promise.race
- Promise.resolve
- Promise.reject
- Promise.allSettled
- Promise.any
Promise封装ajax
function querystring(obj) {
if (Object.prototype.toString.call(obj) === '[object Object]') {
let arr = [];
for (let key in obj) {
arr.push(key + '=' + obj[key]);
}
return arr.join('&');
}
return obj;
}
// promise封装ajax插件
function ajax(options = {}) { //设置默认值为空对象 options:配置参数,输入的参数
// 一.配置默认参数
const settings = {
// 1.配置请求方式,默认为get请求
type: options.type || 'get',
// 2.配置接口地址,没有默认值
url: options.url,
// 3.配置是否异步,默认是异步
async: options.async || true,
// 4.配置获取的数据类型,默认字符串
dataType: options.dataType || 'string',
// 5.配置数据,默认为空
data: options.data || '',
// 6.配置请求头
headers: {
...options.headers
}
};
// 二.检查属性是否符合规范
// 1.检查type属性,要么属性为空,要么输入get和post,正则
if (!/^(get|post)$/i.test(settings.type)) {
throw new Error('目前的请求方式仅支持get和post,其他方式有待更新');
}
// 2.检查url,必须填写,不能为空
if (!settings.url) {
throw new Error('接口地址必须填写,不能为空');
}
// 3.检查是否异步,值必须是布尔值。
if (!(typeof settings.async === 'boolean')) {
throw new Error('是否异步的值只能是true和false');
}
// 4.检查数据类型dataType
if (!(/^(json|string)$/i.test(settings.dataType))) {
throw new Error('获取的数据类型只能是字符串和json对象输出');
}
// 5.检查数据格式,只支持字符串和对象
if (!(typeof settings.data === 'string' || Object.prototype.toString.call(settings.data) === '[object Object]')) {
throw new Error('传输的数据格式不符合规范,请采用字符串或者对象格式');
}
// 6.检查headers格式,格式的值必须是对象。
const queryFormat = ['application/x-www-form-urlencoded', 'multipart/form-data', 'application/json'];
if (settings.headers['content-type'] && queryFormat.indexOf(settings.headers['content-type']) === -1) {
throw new Error('请检查header里面的content-type的值是否正确');
}
// 7.如果存在数据,是对象格式,转换成拼接的格式&,判断请求方式是get,拼接在地址栏的后面
if (settings.data && /^get$/i.test(settings.type)) {
settings.url += '?' + querystring(settings.data)
}
// 三.利用ajax+promise进行参数的应用
const promise = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// alert(1);
xhr.open(settings.type, settings.url, settings.async);
// 如果数据存在,同时是post方式,设置请求头,利用send发送
// 判断是否存在header属性
// 判断是否存在content-type,获取属性值,添加到请求头里面,post请求
if (settings.headers['content-type'] && /^post$/i.test(settings.type)) {
xhr.setRequestHeader('content-type', settings.headers['content-type']);
}
// 判断token
if (settings.headers['authorization']) {
xhr.setRequestHeader('authorization', settings.headers['authorization']);
}
/^post$/i.test(settings.type) ? xhr.send(querystring(settings.data)) : xhr.send()
xhr.onload = function () {
if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
let res = null;
if (settings.dataType.toLowerCase() === 'json') {
try {
res = JSON.parse(xhr.responseText);
} catch (e) {
res = xhr.responseText
}
} else {
res = xhr.responseText;
}
resolve(res);
} else {
reject('接口地址有误')
}
};
})
return promise;
}
// 返回promise对象
const token = 'fdaskfjdsalfjldksafjlkdsajflasdf';
ajax({
type: 'get', //请求类型
url: 'http://localhost:8888/goods/list', //接口地址
async: false, //是否异步
dataType: 'json', //获取数据类型json/string
data: { //a=1&b=2
a: 1,
b: 2,
c: 3
},
headers: { //设置请求头
'content-type': 'application/x-www-form-urlencoded',
'authorization': token
}
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
});