文章目录
AJAX
AJAX 是浏览器与服务器进行数据通信的技术,AJAX是异步的JavaScript和XML,就是使用XMLHttpRequest对象与服务器通信,它可以使用JSON、XML、HTML和text文本等格式发送和接收数据。AJAX最大特点是异步,可以不刷新页面的情况下与服务器通信,交换数据。
XMLHttpRequest
AJAX是基于XMLHttpRequest进行实现,以下是XMLHttpRequest的基本使用。
html
<!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.配置请求方法和url
xhr.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 客户端功能。
javascript
<!-- 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函数,快速收集表单元素的值
javascript
<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>
上传图片
html
<!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对象用于表示一个异步操作的最终完成或失败及其结果值。基本语法:
javascript
// 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的核心设计思想。
javascript
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。
javascript
async function fetchData() {
const res = await fetch('/api/data'); // 等待 Promise 完成
const data = await res.json();
return data; // 自动包装成 Promise
}
// 调用
fetchData().then(data => console.log(data));
等价于
javascript
function fetchData() {
return fetch('/api/data')
.then(res => res.json())
.then(data => data); // 返回值自动被 Promise.resolve 包装
}
回调地狱问题
在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱,可读性差,异常无法获取,耦合性严重,牵一发动全身
javascript
/**
* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
*/
// 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链式调用进行优化,可以使代码更加清晰。
javascript
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会阻止"异步函数内"代码继续执行,原地等待结果)
javascript
// 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 = pname
document.querySelector('.city').innerHTML = cname
document.querySelector('.area').innerHTML = areaName
}
getData()
封装简易Axios
使用Promise+XMLHttpRequest封装简易的axios
javascript
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
javascript
// 使用值解析
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
javascript
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 被拒绝。
javascript
// 所有 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 完成(无论成功或失败)
javascript
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
javascript
// 第一个 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
javascript
// 第一个成功的 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); // true
console.log(error.errors); // ["错误A", "错误B", "错误C"]
});
Promise.try() (非标准,但常用)
立即执行异步函数,同步错误也会被捕获
javascript
// 模拟实现(非原生方法)
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));