AJAX和Promise
文章目录
- AJAX
- XMLHttpRequest
- Axios使用
- Promise
- 基本语法
- Promise的基本原理
- 回调地狱问题
- 封装简易Axios
- 事件循环-EventLoop
- Promise静态方法
- Promise.resolve()
- Promise.reject()
- Promise.all()
- Promise.allSettled()
- Promise.race()
- Promise.any()
- Promise.try() (非标准,但常用)
AJAX
AJAX 是浏览器与服务器进行数据通信的技术,AJAX是异步的JavaScript和XML,就是使用XMLHttpRequest对象与服务器通信,它可以使用JSON、XML、HTML和text文本等格式发送和接收数据。AJAX最大特点是异步,可以不刷新页面的情况下与服务器通信,交换数据。
XMLHttpRequest
AJAX是基于XMLHttpRequest进行实现,以下是XMLHttpRequest的基本使用。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div class="myp"></div><script>// 1.创建XMLHttpRequest对象const xhr = new XMLHttpRequest()// 2.配置请求方法和urlxhr.open('GET', '') // 3.配置监听loadend事件,接收响应结果xhr.addEventListener('loadend', () => {console.log(xhr.response);const data = JSON.parse(xhr.response)console.log(data.list.join('<br>'));document.querySelector('.myp').innerHTML = data.list.join('<br>')})// 4.发起请求xhr.send()</script>
</body>
</html>
Axios使用
Axios 是一个基于Promise的网络请求库,在现代前端开发中,Axios 已经成为事实上的标准,提供了更现代化、更强大的 HTTP 客户端功能。
<!-- axios库地址CDN -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>axios({url: '目标资源地址',method: '请求方法',params: { 参数名: 值}, // 查询参数data: {参数名: 值} // 提交数据
}).then(result => {console.log(result)
}).catch(error => {// 错误处理
})
</script>
Http请求方法
| 请求方法 | 操作 |
|---|---|
| GET | 获取数据 |
| POST | 数据提交 |
| PUT | 修改数据(全部) |
| DELETE | 删除数据 |
| PATCH | 修改数据(部分) |
form-serialize 插件
使用serialize函数,快速收集表单元素的值
<script src="./lib/form-serialize.js"></script>
<script>document.querySelector('.btn').addEventListener('click', () => {/*** 2. 使用serialize函数,快速收集表单元素的值* 参数1:要获取哪个表单的数据* 表单元素设置name属性,值会作为对象的属性名* 建议name属性的值,最好和接口文档参数名一致* 参数2:配置对象* hash 设置获取数据结构* - true:JS对象(推荐)一般请求体里提交给服务器* - false: 查询字符串* empty 设置是否获取空值* - true: 获取空值(推荐)数据结构和标签结构一致* - false:不获取空值*/const form = document.querySelector('.example-form')const data = serialize(form, { hash: true, empty: true })// const data = serialize(form, { hash: false, empty: true })// const data = serialize(form, { hash: true, empty: false })console.log(data)})
</script>
上传图片
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><input type="file" class="upload"><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>document.querySelector('.upload').addEventListener('click', e => {console.log(e.target.files[0]);const fd = new FormData()fd.append('img', e.target.files[0])axios({url: '',method: 'post',data: fd})})</script>
</body>
</html>
Promise
基本语法
Promise对象用于表示一个异步操作的最终完成或失败及其结果值。基本语法:
// 1.创建Promise对象
const p = new Promise((resolve, reject) => {// 2.执行异步代码// 成功调用 resolve('模拟AJAX请求-成功结果')// 失败调用 reject(new Error('模拟AJAX请求-失败结果'))
})
// 3.获取结果
p.then(result => {// 成功
}).catch(error => {// 失败
})
Promise的基本原理
把“将来会得到的结果”封装成一个对象,并允许你现在就注册“成功/失败时要做什么”。换句话说,Promise是一个“未来值”的占位符 + 回调管理器。
以下是Promise的一个简易实现,用于理解Promise的核心设计思想。
function SimplePromise(executor) {let state = 'pending'; // 'pending' | 'fulfilled' | 'rejected'let value; // 成功的值let reason; // 失败的原因let onFulfilledCallbacks = [];let onRejectedCallbacks = [];const resolve = (val) => {if (state !== 'pending') return;state = 'fulfilled';value = val;onFulfilledCallbacks.forEach(cb => cb(value));};const reject = (err) => {if (state !== 'pending') return;state = 'rejected';reason = err;onRejectedCallbacks.forEach(cb => cb(reason));};try {executor(resolve, reject);} catch (e) {reject(e);}this.then = function(onFulfilled, onRejected) {return new SimplePromise((resolveNext, rejectNext) => {// 成功处理函数const handleFulfilled = (val) => {try {const result = onFulfilled(val);resolveNext(result);} catch (e) {rejectNext(e);}};// 失败处理函数const handleRejected = (err) => {try {const result = onRejected ? onRejected(err) : err;// 如果用户没传 onRejected,就继续抛出错误(错误冒泡)if (onRejected) {resolveNext(result); // 注意:catch 后返回的是成功值!} else {rejectNext(result);}} catch (e) {rejectNext(e);}};if (state === 'fulfilled') {handleFulfilled(value);} else if (state === 'rejected') {handleRejected(reason);} else {onFulfilledCallbacks.push(handleFulfilled);onRejectedCallbacks.push(handleRejected);}});};
}
async / await 是 JavaScript 中用于处理异步操作的语法糖,底层完全基于 Promise,await 本质上是 .then() 的语法糖,而 async 函数总是返回一个 Promise。
async function fetchData() {const res = await fetch('/api/data'); // 等待 Promise 完成const data = await res.json();return data; // 自动包装成 Promise
}// 调用
fetchData().then(data => console.log(data));
等价于
function fetchData() {return fetch('/api/data').then(res => res.json()).then(data => data); // 返回值自动被 Promise.resolve 包装
}
回调地狱问题
在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱,可读性差,异常无法获取,耦合性严重,牵一发动全身
/*** 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中*/// 1. 获取默认第一个省份的名字axios({url: 'http://xxx/api/province'}).then(result => {const pname = result.data.list[0]document.querySelector('.province').innerHTML = pname// 2. 获取默认第一个城市的名字axios({url: 'http://xxx/api/city', params: { pname }}).then(result => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 3. 获取默认第一个地区的名字axios({url: 'http://xxx/api/area', params: { pname, cname }}).then(result => {console.log(result)const areaName = result.data.list[0]document.querySelector('.area').innerHTML = areaName})})}).catch(error => {console.dir(error)})
使用Promise链式调用进行优化,可以使代码更加清晰。
let pname = ''// 1. 得到-获取省份Promise对象axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {pname = result.data.list[0]document.querySelector('.province').innerHTML = pname// 2. 得到-获取城市Promise对象return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})}).then(result => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 3. 得到-获取地区Promise对象return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})}).then(result => {console.log(result)const areaName = result.data.list[0]document.querySelector('.area').innerHTML = areaName})
使用async和await语法,解决回调函数地狱
在async函数内,使用await关键字,获取Promise对象"成功状态"结果值
注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
// 1. 定义async修饰函数async function getData() {// 2. await等待Promise对象成功的结果const pObj = await axios({url: 'http://hmajax.itheima.net/api/province'})const pname = pObj.data.list[0]const cObj = await axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})const cname = cObj.data.list[0]const aObj = await axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})const areaName = aObj.data.list[0]document.querySelector('.province').innerHTML = pnamedocument.querySelector('.city').innerHTML = cnamedocument.querySelector('.area').innerHTML = areaName}getData()
封装简易Axios
使用Promise+XMLHttpRequest封装简易的axios
function myAxios(config) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest()if(config.params) {const paramObj = new URLSearchParams(config.params)const queryStr = paramObj.toString()config.url += `?${queryStr}`}xhr.open(config.method || 'GET', config.url)xhr.addEventListener('loadend', () => {if (xhr.status >= 200 && xhr.status < 300) {resolve(JSON.parse(xhr.response))} else {reject(new Error(xhr.response))}})if(config.data) {xhr.setRequestHeader('Content-Type', 'application/json')xhr.send(JSON.stringify(data))} else {xhr.send()}})
}
myAxios({url: ''
}).then(result => {console.log(result);
}).catch(err => {console.log(err);
})
事件循环-EventLoop
ES6 之后引入了 Promise 对象, 让 JS 引擎也可以发起异步任务
异步任务分为:
- 宏任务:由浏览器环境执行的异步代码
- 微任务:由 JS 引擎环境执行的异步代码,Promise对象.then()中的代码为微任务

Promise静态方法
Promise.resolve()
创建一个立即解析的 Promise
// 使用值解析
Promise.resolve("成功").then(value => {console.log(value); // 输出: "成功"
});// 解析一个 Promise
const original = Promise.resolve("原始值");
const wrapped = Promise.resolve(original);
wrapped.then(value => {console.log(value); // 输出: "原始值"
});// 解析 thenable 对象
Promise.resolve({then(resolve, reject) {resolve("thenable 对象");}
}).then(value => {console.log(value); // 输出: "thenable 对象"
});
Promise.reject()
创建一个立即拒绝的 Promise
Promise.reject(new Error("操作失败")).catch(error => {console.error(error.message); // 输出: "操作失败"});// 在 async 函数中使用
async function example() {try {await Promise.reject("拒绝原因");} catch (error) {console.log(error); // 输出: "拒绝原因"}
}
example();
Promise.all()
等待所有 Promise 完成,或第一个 Promise 被拒绝。
// 所有 Promise 都成功
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);Promise.all([promise1, promise2, promise3]).then(values => {console.log(values); // 输出: [1, 2, 3]});// 其中一个 Promise 失败
const successPromise = Promise.resolve("成功");
const failurePromise = Promise.reject(new Error("失败"));Promise.all([successPromise, failurePromise]).then(values => {console.log(values); // 不会执行}).catch(error => {console.error(error.message); // 输出: "失败"});// 实际应用:并行请求多个 API
const fetchUser = Promise.resolve({ name: "张三" });
const fetchPosts = Promise.resolve([{ id: 1, title: "文章1" }]);
const fetchComments = Promise.resolve([{ id: 1, content: "评论1" }]);Promise.all([fetchUser, fetchPosts, fetchComments]).then(([user, posts, comments]) => {console.log("用户:", user);console.log("文章:", posts);console.log("评论:", comments);});
Promise.allSettled()
等待所有 Promise 完成(无论成功或失败)
const resolvedPromise = Promise.resolve("成功");
const rejectedPromise = Promise.reject("失败");Promise.allSettled([resolvedPromise, rejectedPromise]).then(results => {results.forEach((result, index) => {if (result.status === "fulfilled") {console.log(`Promise ${index}:`, result.value);} else {console.log(`Promise ${index}:`, result.reason);}});// 输出:// Promise 0: 成功// Promise 1: 失败});
Promise.race()
返回第一个完成(成功或失败)的 Promise
// 第一个 Promise 先完成
const fastPromise = new Promise(resolve => {setTimeout(() => resolve("快的"), 100);
});const slowPromise = new Promise(resolve => {setTimeout(() => resolve("慢的"), 500);
});Promise.race([fastPromise, slowPromise]).then(result => {console.log(result); // 输出: "快的"});// 超时控制
function timeout(ms) {return new Promise((_, reject) => {setTimeout(() => reject(new Error("超时")), ms);});
}function fetchWithTimeout(url, timeoutMs) {return Promise.race([fetch(url),timeout(timeoutMs)]);
}// 模拟使用
const mockFetch = Promise.resolve("数据获取成功");
fetchWithTimeout(mockFetch, 2000).then(data => console.log(data)).catch(error => console.error(error.message));
Promise.any()
返回第一个成功的 Promise,如果所有 Promise 都失败则抛出 AggregateError
// 第一个成功的 Promise
const failure1 = Promise.reject("错误1");
const failure2 = Promise.reject("错误2");
const success = Promise.resolve("成功");Promise.any([failure1, failure2, success]).then(result => {console.log(result); // 输出: "成功"});// 所有 Promise 都失败
const allFailures = [Promise.reject("错误A"),Promise.reject("错误B"),Promise.reject("错误C")
];Promise.any(allFailures).catch(error => {console.log(error instanceof AggregateError); // trueconsole.log(error.errors); // ["错误A", "错误B", "错误C"]});
Promise.try() (非标准,但常用)
立即执行异步函数,同步错误也会被捕获
// 模拟实现(非原生方法)
Promise.try = function(fn) {return new Promise(resolve => resolve(fn()));
};// 使用示例
function asyncOperation() {// 可能抛出同步错误if (Math.random() > 0.5) {throw new Error("同步错误");}return "操作成功";
}// 传统方式需要 try-catch
try {asyncOperation().then(console.log);
} catch (error) {console.error("捕获错误:", error.message);
}// 使用 Promise.try
Promise.try(asyncOperation).then(result => console.log(result)).catch(error => console.error("捕获错误:", error.message));
