哈喽大家好,我是Lotzinfly,一位前端小猎人。欢迎大家来到前端丛林,在这里你将会遇到各种各样的前端猎物,我希望可以把这些前端猎物统统拿下,嚼碎了服用,并成为自己身上的骨肉。当我们学习前端的时候,Promise是重中之重。学会Promise将大大提高我们的开发效率,所以一定要掌握好Promise基本用法。
Promise 就像煮泡面------这看似简单的日常操作,实则暗藏玄机。同样是一包泡面,有人煮出的面软塌无味,有人却能通过精准控制火候、调料配比,让一碗普通泡面焕发出令人惊艳的美味。Promise 亦是如此,表面上看只需 new Promise()
加几个 .then()
就能实现异步操作,但想要写出真正优雅高效的代码,却需要掌握一系列关键技巧。就像泡面需要把握煮面的时间、水量的多少、调料的顺序,Promise 的使用也需要对链式调用、错误处理、并发控制等细节精雕细琢。
许多开发者初学 Promise 时,往往陷入"套娃式"的回调地狱,代码层层嵌套如同乱麻;或是忽略错误处理,导致程序在异常时直接崩溃;又或在处理多个异步任务时,采用低效的串行方式,白白浪费性能。这些痛点就像泡面煮得过软或过硬一样,让原本应该顺畅的异步流程变得艰难而低效。
但别担心!本文将为你揭秘 8 个经过实战检验的 Promise 奇淫技巧😏😏😏,涵盖从基础到进阶的各种场景。无论是避免回调地狱的链式调用、确保程序健壮性的 .catch()
保险,还是提升性能的并发控制方法 Promise.all()
,亦或是让代码更清晰的 async/await
语法,这些技巧都将帮助你突破异步编程的瓶颈。掌握它们后,你的 Promise 代码将如同经过大厨精心调制的泡面------结构清晰、运行稳健、效率出众,真正实现从"勉强能用"到"优雅高效"的蜕变。让我们系好围裙,拿起"代码锅铲",一起开启这场 Promise 的美味进化之旅吧!
1. 链式调用
原文用例 :
错误示范(套娃式写法):
js
getUser().then(user => {
getOrders(user.id).then(orders => {
getOrderDetails(orders[0].id).then(details => {
console.log(details); // 又回到地狱了!
});
});
});
正确姿势(链式调用):
js
getUser()
.then(user => getOrders(user.id))
.then(orders => getOrderDetails(orders[0].id))
.then(details => console.log(details))
.catch(error => console.error('出错了:', error));
扩展例子:
js
function fetchUserProfile(userId) {
return fetchUser(userId)
.then(user => fetchUserPosts(user.id))
.then(posts => fetchPostComments(posts[0].id))
.then(comments => console.log('First post comments:', comments))
.catch(error => console.error('Error fetching user profile:', error));
}
2. 一定要加.catch()保险
原文用例 :
错误示范(裸奔很危险):
js
fetchData().then(data => {
// 万一出错,程序就崩了!
});
正确姿势(安全第一):
js
fetchData()
.then(data => console.log(data))
.catch(error => {
console.error('捕获错误:', error); // 还可以在这里做错误恢复操作
});
扩展例子:
js
function fetchDataSafely() {
return fetchDataFromApi()
.then(data => processData(data))
.catch(error => {
console.error('Failed to fetch data:', error);
return fallbackData(); // 返回备用数据
});
}
3. 用Promise.all()同时处理多个任务
原文用例:
js
const [user, orders, notifications] = await Promise.all([
fetchUser(),
fetchOrders(),
fetchNotifications()
]);
console.log('所有数据都拿到了!');
扩展例子:
js
async function fetchAllData() {
try {
const [userInfo, orderHistory, productRecommendations] = await Promise.all([
fetchUserInfo(),
fetchOrderHistory(),
fetchProductRecommendations()
]);
console.log('User Info:', userInfo);
console.log('Order History:', orderHistory);
console.log('Product Recommendations:', productRecommendations);
} catch (error) {
console.error('Failed to fetch all data:', error);
}
}
4. 别忘了Promise.race()竞速赛
原文用例:
js
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('请求超时')), 5000);
});
const data = await Promise.race([fetchData(), timeout]);
扩展例子:
js
function fetchWithTimeout(url, timeoutMs) {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs);
});
return Promise.race([
fetch(url),
timeout
]);
}
// 使用
fetchWithTimeout('https://api.example.com/data', 3000)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
5. 善用async/await让代码更清晰
原文用例:
js
// before: then链
function getUserData() {
return getUser()
.then(user => getOrders(user.id))
.then(orders => getDetails(orders[0].id));
}
// after: async/await
async function getUserData() {
try {
const user = await getUser();
const orders = await getOrders(user.id);
const details = await getDetails(orders[0].id);
return details;
} catch (error) {
console.error('获取数据失败:', error);
throw error; // 重新抛出错误
}
}
扩展例子:
js
async function processOrder(orderId) {
try {
const order = await fetchOrder(orderId);
const customer = await fetchCustomer(order.customerId);
const shippingAddress = await fetchShippingAddress(order.shippingAddressId);
console.log('Order:', order, 'Customer:', customer, 'Shipping Address:', shippingAddress);
} catch (error) {
console.error('Failed to process order:', error);
throw error;
}
}
6. 避免在循环中滥用await
原文用例 :
错误示范(一个个等,慢死了):
js
for (const id of ids) {
const data = await fetchItem(id); // 等完一个再下一个
}
正确姿势(一起请求,快多了):
js
const promises = ids.map(id => fetchItem(id));
const results = await Promise.all(promises);
扩展例子:
js
async function fetchMultipleItems(itemIds) {
try {
const fetchPromises = itemIds.map(id => fetchItemDetails(id));
const items = await Promise.all(fetchPromises);
console.log('Fetched items:', items);
} catch (error) {
console.error('Failed to fetch items:', error);
}
}
7. 合理处理错误,别一棍子打死
原文用例:
js
try {
const user = await getUser();
const orders = await getOrders(user.id);
} catch (error) {
if (error.type === 'USER_NOT_FOUND') {
redirectToLogin();
} else if (error.type === 'NETWORK_ERROR') {
showRetryButton();
} else {
showErrorMessage('系统繁忙,请稍后再试');
}
}
扩展例子:
js
async function updateUserProfile(userId, profileData) {
try {
const user = await fetchUser(userId);
const updatedUser = await updateUser(userId, profileData);
console.log('User profile updated:', updatedUser);
} catch (error) {
if (error.code === 'NOT_FOUND') {
console.error('User not found');
// 创建用户或显示错误
} else if (error.code === 'INVALID_DATA') {
console.error('Invalid profile data');
// 显示表单验证错误
} else {
console.error('Failed to update user profile:', error);
// 显示通用错误消息
}
}
}
8. 用Promise化改造回调函数
原文用例:
js
// 传统的回调函数
function oldSchoolMethod(data, callback) {
// 一些异步操作...
}
// 包装成Promise
function modernMethod(data) {
return new Promise((resolve, reject) => {
oldSchoolMethod(data, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
// 现在可以愉快地用了!
const result = await modernMethod(data);
扩展例子:
js
// 传统的文件读取回调函数
function readFileCallback(filePath, callback) {
// 模拟异步文件读取
setTimeout(() => {
if (filePath === 'valid.txt') {
callback(null, 'File content');
} else {
callback(new Error('File not found'));
}
}, 100);
}
// 包装成Promise
function readFilePromise(filePath) {
return new Promise((resolve, reject) => {
readFileCallback(filePath, (error, content) => {
if (error) {
reject(error);
} else {
resolve(content);
}
});
});
}
// 使用
async function readFileAndProcess() {
try {
const content = await readFilePromise('valid.txt');
console.log('File content:', content);
} catch (error) {
console.error('Failed to read file:', error);
}
}
通过这些详细的用例和扩展例子,可以更好地理解和应用Promise的优化技巧,使异步代码更加优雅和高效。