8 个经过实战检验的 Promise 奇淫技巧你需要掌握😏😏😏

哈喽大家好,我是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的优化技巧,使异步代码更加优雅和高效。

相关推荐
RoyLin2 小时前
TypeScript设计模式:单例模式
前端·后端·node.js
小公主2 小时前
我的第一个 React Flow 小实验
前端
RoyLin2 小时前
TypeScript设计模式:工厂方法模式
前端·后端·node.js
知其然亦知其所以然2 小时前
MySQL 社招必考题:如何优化查询过程中的数据访问?
后端·mysql·面试
掘金酱2 小时前
🎉 2025年8月金石计划开奖公示
前端·人工智能·后端
Cache技术分享2 小时前
191. Java 异常 - 捕获与处理异常
前端·后端
努力的小郑2 小时前
从一次分表实践谈起:我们真的需要复杂的分布式ID吗?
分布式·后端·面试
RoyLin2 小时前
TypeScript设计模式:模板方法模式
前端·后端·node.js