惊!10行代码实现fetch并发请求!前端工程师必看的错误处理神操作

引言

在如今这个追求极致用户体验的前端开发时代,页面加载速度数据获取效率堪称是前端工程师的"命根子"。想象一下,当用户打开一个页面,需要同时获取用户信息、商品列表、推荐内容等多个数据接口时,一个个顺序发送请求,那等待时间简直能把用户"劝退"!而fetch API作为现代前端开发中数据请求的"主力军",如何用它实现并发请求,并优雅处理可能出现的错误,就成了每个前端工程师必须掌握的硬核技能。今天,咱就用大白话唠一唠,10行代码就能搞定的fetch并发请求及错误处理的神操作!

一、什么是fetch API?为啥它这么火?

fetch API是浏览器提供的一个用于网络请求的接口,相比老一代的XMLHttpRequest(简称XHR),它使用起来更加简洁、直观,而且支持Promise,这对于喜欢用async/await语法糖的前端小伙伴来说,简直是"梦中情接口"!它就像是一个超级能干的"快递员",能帮我们从服务器那里把数据"搬"回来,不管是GET请求获取数据,还是POST请求提交数据,它都能轻松胜任。在ReactVue等主流前端框架中,fetch API的身影随处可见,已然成为前端开发的"标配"技能。

二、痛点:传统顺序请求的"致命伤"

在没有使用并发请求之前,很多小伙伴可能会这样写代码来获取多个数据:

javascript 复制代码
// 发送第一个请求,获取用户信息
fetch('https://example.com/api/user')
   .then(response => response.json())
   .then(data => {
        console.log('用户信息:', data);
        // 第一个请求成功后,再发送第二个请求,获取商品列表
        return fetch('https://example.com/api/products');
    })
   .then(response => response.json())
   .then(data => {
        console.log('商品列表:', data);
        // 第二个请求成功后,再发送第三个请求,获取推荐内容
        return fetch('https://example.com/api/recommendations');
    })
   .then(response => response.json())
   .then(data => {
        console.log('推荐内容:', data);
    })
   .catch(error => {
        console.error('请求出错:', error);
    });

这种写法虽然能实现需求,但问题非常明显!每个请求都要等上一个请求完成后才能发送,假如第一个请求因为网络延迟等原因卡住了,后面的请求都得"干等着",页面加载速度直接"拉胯",用户体验也会变得极差。而且,这样的代码看起来十分冗长,维护起来也很麻烦。这就是传统顺序请求的"致命伤",也是我们迫切需要并发请求的原因!

三、解决方案:fetch并发请求闪亮登场

fetch实现并发请求的核心思路其实很简单,就是同时发送多个请求,然后等所有请求都完成后,再统一处理结果。这就好比我们点外卖,一次点了三家店的美食,不用等第一家送来了再点第二家,而是同时下单,等三家都做好送过来后再一起享受。在JavaScript中,我们可以借助Promise.all方法来实现这个功能。Promise.all接受一个Promise数组作为参数,当数组中的所有Promise都成功时,它会返回一个包含所有成功结果的数组;只要有一个Promise失败,它就会立即返回失败的结果。下面是具体的代码实现:

javascript 复制代码
// 定义一个函数,用于发送单个fetch请求并返回Promise
const fetchData = (url) => {
    return fetch(url)
       .then(response => {
            // 检查响应状态,如果不是200-299之间的状态码,就抛出错误
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.json();
        });
};

// 定义要发送请求的URL数组
const urls = [
    'https://example.com/api/user',
    'https://example.com/api/products',
    'https://example.com/api/recommendations'
];

// 使用Promise.all实现并发请求
Promise.all(urls.map(fetchData))
   .then(data => {
        // 所有请求都成功时,打印结果
        console.log('所有请求结果:', data);
    })
   .catch(error => {
        // 只要有一个请求失败,就捕获错误并打印
        console.error('请求出错:', error);
    });

在这段代码中:

  1. 首先定义了一个fetchData函数,这个函数接受一个url参数,使用fetch发送请求。在请求成功后,通过response.ok检查响应状态,如果状态码不是200-299之间(表示请求成功的状态码范围),就会抛出一个错误;如果状态码正常,就将响应数据解析为JSON格式并返回。
  2. 然后定义了一个urls数组,里面存放着我们需要请求的多个接口地址。
  3. 最后使用Promise.all,并通过urls.map(fetchData)将每个url都调用fetchData函数生成对应的Promise,组成一个Promise数组传入Promise.all。这样就实现了同时发送多个fetch请求,当所有请求都完成后,会在.then回调中得到包含所有请求结果的数组;如果有任何一个请求失败,就会在.catch回调中捕获到错误。

四、进阶:更灵活的并发请求处理------Promise.allSettled

虽然Promise.all能满足大部分并发请求的需求,但它有一个"致命缺点":只要有一个请求失败,整个Promise.all就会立即失败,后面还没完成的请求结果就得不到了。有时候我们希望不管请求成功还是失败,都能知道每个请求的最终状态,这时候就可以使用Promise.allSettled方法。它同样接受一个Promise数组作为参数,但它会等所有Promise都" settled"(即要么成功,要么失败)后,返回一个包含每个Promise结果对象的数组,每个对象都有status('fulfilled' 或'rejected')和value(成功结果)或reason(失败原因)属性。代码如下:

javascript 复制代码
// 还是使用之前定义的fetchData函数
const fetchData = (url) => {
    return fetch(url)
       .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.json();
        });
};

const urls = [
    'https://example.com/api/user',
    'https://example.com/api/products',
    'https://example.com/api/recommendations'
];

// 使用Promise.allSettled实现并发请求
Promise.allSettled(urls.map(fetchData))
   .then(results => {
        results.forEach(result => {
            if (result.status === 'fulfilled') {
                console.log('请求成功,结果:', result.value);
            } else {
                console.error('请求失败,原因:', result.reason);
            }
        });
    });

在这段代码中,Promise.allSettled会等所有fetch请求都有结果后,返回一个results数组。我们通过遍历results数组,根据每个结果对象的status属性来判断请求是成功还是失败,并分别进行处理。这样即使有部分请求失败,我们也能获取到其他请求的结果,对整个并发请求的情况有更全面的了解。

五、错误处理:让请求更加"稳如老狗"

在实际开发中,除了请求本身失败(比如网络错误、服务器返回错误状态码),还可能会遇到其他各种问题,比如用户在请求过程中关闭了页面,或者fetch不被浏览器支持等情况。为了让我们的代码更加健壮,还需要对这些情况进行处理。

  1. 网络错误处理 :当网络出现问题,比如用户断网了,fetch会抛出一个TypeError。我们可以在fetchData函数中捕获这个错误,给用户一个友好的提示:
javascript 复制代码
const fetchData = (url) => {
    return fetch(url)
       .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.json();
        })
       .catch(error => {
            if (error instanceof TypeError) {
                console.error('网络错误,请检查网络连接!');
            } else {
                console.error('请求出错:', error);
            }
            // 这里可以选择将错误继续抛出,让上层调用者处理,也可以返回一个默认值
            throw error;
        });
};
  1. 浏览器兼容性处理 :虽然fetch API已经得到了广泛支持,但在一些老旧浏览器中可能不支持。我们可以在使用fetch之前进行检测,如果不支持,就使用XHR作为替代方案:
javascript 复制代码
const fetchData = (url) => {
    if (!window.fetch) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        resolve(JSON.parse(xhr.responseText));
                    } else {
                        reject(new Error(`HTTP error! status: ${xhr.status}`));
                    }
                }
            };
            xhr.onerror = (error) => {
                reject(error);
            };
            xhr.send();
        });
    }
    return fetch(url)
       .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.json();
        })
       .catch(error => {
            if (error instanceof TypeError) {
                console.error('网络错误,请检查网络连接!');
            } else {
                console.error('请求出错:', error);
            }
            throw error;
        });
};

通过这些额外的错误处理,我们的fetch并发请求代码就能应对更多复杂的情况,变得更加"稳如老狗"!

六、总结

通过本文的学习,我们了解了fetch API的强大之处,以及如何使用它实现并发请求和优雅地处理错误。无论是Promise.all还是Promise.allSettled,都为我们提供了高效处理多个请求的方式;而全面的错误处理机制,则让我们的代码在各种复杂环境下都能稳定运行。在当今竞争激烈的前端开发领域,掌握这些技能,能让我们的页面性能大幅提升,用户体验更加出色,也能让我们在技术浪潮中脱颖而出!赶紧把这些知识运用到实际项目中吧,相信你会收获满满!

相关推荐
懒羊羊我小弟几秒前
React Router v7 从入门到精通指南
前端·react.js·前端框架
DC...31 分钟前
vue滑块组件设计与实现
前端·javascript·vue.js
RationalDysaniaer31 分钟前
Go设计模式-观察者模式
观察者模式·设计模式·golang
Mars狐狸40 分钟前
AI项目改用服务端组件实现对话?包体积减小50%!
前端·react.js
H5开发新纪元1 小时前
Vite 项目打包分析完整指南:从配置到优化
前端·vue.js
嘻嘻嘻嘻嘻嘻ys1 小时前
《Vue 3.3响应式革新与TypeScript高效开发实战指南》
前端·后端
千千寰宇1 小时前
[设计模式/Java] 设计模式之解释器模式【27】
数据库·设计模式
恋猫de小郭1 小时前
腾讯 Kuikly 正式开源,了解一下这个基于 Kotlin 的全平台框架
android·前端·ios
2301_799404911 小时前
如何修改npm的全局安装路径?
前端·npm·node.js
(❁´◡双辞`❁)*✲゚*1 小时前
node入门和npm
前端·npm·node.js