Promise 与 async/await 的异同点和在VUE与小程序中的应用
Promise:通过.then()和.catch()进行异步处理,适合简单任务,但在复杂情况下可读性下降。:使异步代码看起来像同步代码,更加易读,错误处理更加直观。在封装 API 请求时,建议使用以提高代码的可维护性,无论是在 Vue.js 还是小程序中。
在前端开发中,无论是 Vue.js 还是小程序,使用 Promise 和 async/await 来封装请求都可以提高代码的可读性和可维护性。下面我们将讨论它们的异同点,并提供示例代码。
一、Promise 与 async/await 的异同点
1.相同点
- 异步处理:
Promise和async/await都用于处理异步操作,允许代码在等待某个操作结果的时候不会阻塞执行。 - 基于Promise:
async/await语法实际上是基于Promise的,所有使用await的表达式会返回一个Promise。 - 错误处理:两者都可以使用
.catch()或try...catch来处理可能出现的错误。
2.不同点
-
语法结构:
- Promise:使用
.then()和.catch()方法链式处理异步结果。const myPromise = new Promise((resolve, reject) => { // 异步操作 }); myPromise .then(result => { // 处理成功 }) .catch(error => { // 处理失败 }); - async/await:使用
async函数和await关键字,使代码看起来更像同步代码。async function myAsyncFunction() { try { const result = await myPromise; // 处理成功 } catch (error) { // 处理失败 } }
- Promise:使用
-
可读性:
- Promise:链式调用可能导致代码嵌套,阅读起来不如
async/await直观。 - async/await:使得异步代码看起来更像同步代码,更加易读和易于维护。
- Promise:链式调用可能导致代码嵌套,阅读起来不如
-
错误处理的方式:
- Promise:错误处理在链的末端,使用
.catch()方法来捕获。 - async/await:可以使用
try...catch结构,这使得错误处理更加灵活和方便,特别是在多个异步操作中。
- Promise:错误处理在链的末端,使用
-
执行顺序:
- Promise:可以很容易处理并行的多个异步操作。
- async/await:默认情况下是按顺序执行的,如果想要并行执行,仍然需要使用
Promise.all()。
3.示例对比
以下是 Promise 和 async/await 的示例对比:
1.使用 Promise
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("数据加载成功!");
}, 1000);
});
}
fetchData()
.then(data => {
console.log(data);
return fetchData();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
2.使用 async/await
async function fetchDataAsync() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("数据加载成功!");
}, 1000);
});
}
async function main() {
try {
const data1 = await fetchDataAsync();
console.log(data1);
const data2 = await fetchDataAsync();
console.log(data2);
} catch (error) {
console.error(error);
}
}
main();
4.封装请求
1.使用 Promise 封装请求
下面的代码示例展示了如何使用 Promise 进行请求封装:
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
// 检查响应状态
if (!response.ok) {
return reject(new Error('网络响应错误'));
}
return response.json(); // 解析为 JSON
})
.then(data => {
resolve(data); // 成功返回数据
})
.catch(error => {
reject(error); // 捕获并返回错误
});
});
}
// 使用示例
fetchData('https://api.example.com/data')
.then(data => {
console.log('获取的数据:', data);
})
.catch(error => {
console.error('请求失败:', error);
});
2.使用 async/await 封装请求
使用 async/await 可以使得代码看起来更简洁。下面是封装请求的示例:
async function fetchData(url) {
try {
const response = await fetch(url); // 等待 fetch 的结果
if (!response.ok) throw new Error('网络响应错误'); // 检查响应状态
const data = await response.json(); // 解析为 JSON
return data; // 返回数据
} catch (error) {
throw error; // 捕获并抛出错误
}
}
// 使用示例
(async () => {
try {
const data = await fetchData('https://api.example.com/data');
console.log('获取的数据:', data);
} catch (error) {
console.error('请求失败:', error);
}
})();
二、在实际开发中注意事项
在实际开发中,使用 Promise 和 async/await 时有一些注意事项,可以帮助开发者更有效地处理异步操作,并避免常见问题。以下是一些关键点:
1. 错误处理
-
Promise: 使用
.catch()方法来捕获和处理错误。但要注意,如果有多层嵌套的 Promise,每层的.catch() 都需要处理错误。fetch('/api/data') .then(response => response.json()) .catch(error => console.error('Error:', error)); -
async/await: 使用
try/catch块可以捕获所有可能的错误,使得错误处理更加集中和清晰。async function fetchData() { try { const response = await fetch('/api/data'); const data = await response.json(); } catch (error) { console.error('Error:', error); } }
2. 不要在循环中直接使用 await
在循环中直接使用 await 可能会导致性能低下,因为这会使每次迭代都等待前一次完成。
-
错误的做法:
for (const item of items) { await processItem(item); // 每次都等待,逐个执行 } -
正确的做法: 使用
Promise.all来并行处理所有异步操作。const promises = items.map(item => processItem(item)); const results = await Promise.all(promises);
3. 保持 async 和 Promise 一致性
- 确保在使用 async/await 的函数中,没有遗漏的 Promise 处理。如果一个函数是 async 的,它应该返回 Promise。
4. 使用 .finally() 处理结束状态
对于 Promise,可以使用 .finally() 来进行清理工作,无论是成功还是失败。这在 async/await 中则需要在 try/catch 的最后进行相应的处理。
fetch('/api/data')
.then(response => response.json())
.catch(error => console.error(error))
.finally(() => {
// 清理工作
});
5. 降低 Promise 链的深度
尽量避免过深的 Promise 链,这会让代码变得更加复杂和难以维护。使用 async/await 可以更好地管理异步操作的逻辑结构。
6. 适当使用 Promise.race
如果需要在多个 Promise 中获得第一个完成的结果,可以使用 Promise.race。在实际开发中,这对于处理超时、并发请求等场景非常有用。
const fetchWithTimeout = (url, timeout) => {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
};
7. 处理未处理的 Promise 拒绝
在 Node.js 环境中,未处理的 Promise 拒绝会导致程序崩溃,可以通过 process.on('unhandledRejection', handler) 捕获这些拒绝并进行处理。
三、封装 Vue 和小程序的 API 请求示例
以下是 Vue 和小程序的请求封装示例,包含 GET、POST、文件上传和下载。
1. Vue.js 示例
// apiService.js
export default class ApiService {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async get(endpoint, params = {}) {
const url = new URL(`${this.baseUrl}${endpoint}`);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
try {
const response = await fetch(url);
return await this.handleResponse(response);
} catch (error) {
console.error(error);
}
}
async post(endpoint, data) {
try {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
return await this.handleResponse(response);
} catch (error) {
console.error(error);
}
}
async uploadFile(endpoint, file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
body: formData,
});
return await this.handleResponse(response);
} catch (error) {
console.error(error);
}
}
async downloadFile(endpoint) {
try {
const response = await fetch(`${this.baseUrl}${endpoint}`);
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = endpoint.split('/').pop();
document.body.appendChild(a);
a.click();
a.remove();
} catch (error) {
console.error(error);
}
}
async handleResponse(response) {
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '请求失败');
}
return response.json();
}
}
2. 小程序示例
// apiService.js
class ApiService {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async get(endpoint, params = {}) {
const url = this.buildUrl(endpoint, params);
return new Promise((resolve, reject) => {
wx.request({
url,
method: 'GET',
success: res => resolve(res.data),
fail: err => reject(err),
});
});
}
async post(endpoint, data) {
return new Promise((resolve, reject) => {
wx.request({
url: `${this.baseUrl}${endpoint}`,
method: 'POST',
data,
header: { 'Content-Type': 'application/json' },
success: res => resolve(res.data),
fail: err => reject(err),
});
});
}
async uploadFile(endpoint, filePath) {
return new Promise((resolve, reject) => {
wx.uploadFile({
url: `${this.baseUrl}${endpoint}`,
filePath,
name: 'file',
success: res => resolve(res.data),
fail: err => reject(err),
});
});
}
async downloadFile(url) {
return new Promise((resolve, reject) => {
wx.downloadFile({
url,
success: res => {
// 处理文件下载逻辑
resolve(res);
},
fail: err => reject(err),
});
});
}
buildUrl(endpoint, params) {
const url = new URL(`${this.baseUrl}${endpoint}`);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
return url.toString();
}
}
总结
- Promise:通过
.then()和.catch()进行异步处理,适合简单任务,但在复杂情况下可读性下降。 - async/await:使异步代码看起来像同步代码,更加易读,错误处理更加直观。
在封装 API 请求时,建议使用 async/await 以提高代码的可维护性,无论是在 Vue.js 还是小程序中。
更多推荐


所有评论(0)