Hello,大家好,我是 Sunday。
前两天有个同学在面试中被问到了一个问题:“如果在请求多个不同的接口,那么应该如何去做?” 该同学回答说:“我们可以把这些接口放到一个数组中,然后通过 for 循环来循环请求!”
嗯...这确是是一个方式,不过这并不好。再加上异步问题现在已经成了面试中的常见问题,所以,今天咱们就来说一下 异步请求的最佳实践,帮助大家解决异步编程,以及面试问题。
我们不应该在循环内使用 await。 而是可以利用 promise.all 方法:
// ❌async function fn(reqs) { const results = []; for (const req of reqs) { // 每次循环迭代都会延迟到整个异步操作完成 results.push(await req); } return results;}// ✅async function fn(reqs) { // 存储所有异步操作的 Promise const promises = reqs.map((req) => req); // 所有异步操作都已经开始,现在等待它们全部完成 const results = await Promise.all(promises); return results}
不要在 Promise 构造函数中返回值。 从那里返回的值是无用的。 它们也不影响 Promise 的状态。
// ❌new Promise((resolve, reject) => { // 返回没有意义 if (b) { return result; }});// ✅new Promise((resolve, reject) => { // 利用 resolve 传递 if (b) { resolve(result); return; }});
看以下代码,你认为最终打印会是多少?
// ❌let totalPosts = 0;async function getPosts(userId) { // 模拟获取用户的帖子数量 const users = [{ id: 1, posts: 5 }, { id: 2, posts: 3 }]; // 模拟异步延迟 await sleep(Math.random() * 1000); // 返回对应用户的帖子数量 return users.find((user) => user.id === userId).posts;}async function sleep (time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve() }, time) })}async function addPosts(userId) { // 将用户的帖子数量加到总帖子数上 totalPosts += await getPosts(userId);}// 并行地获取两个用户的帖子数量,并在全部获取完毕后输出总帖子数await Promise.all([addPosts(1), addPosts(2)]);console.log('帖子数量:', totalPosts);
执行以上代码,你可能会打印 3 或 5,而不是 8。
这个原因就是因为 竞态条件 问题而导致的。当在单独的函数调用中更新值时,更新不会反映在当前函数作用域中。 因此,这两个函数都将其结果添加到初始的 TotalPosts 值 0 中。
以下是避免竞态条件的方式:
// ✅let totalPosts = 0;async function getPosts(userId) { const users = [{ id: 1, posts: 5 }, { id: 2, posts: 3 }]; await sleep(Math.random() * 1000); return users.find((user) => user.id === userId).posts;}async function sleep (time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve() }, time) })}async function addPosts(userId) { const posts = await getPosts(userId); totalPosts += posts; // 变量被读取并立即更新}await Promise.all([addPosts(1), addPosts(2)]);console.log('帖子数量:', totalPosts);
这个问题大家应该很好理解,直接看代码即可
// ❌async1((err, result1) => { async2(result1, (err, result2) => { async3(result2, (err, result3) => { async4(result3, (err, result4) => { console.log(result4); }); }); });});// ✅const result1 = await asyncPromise1();const result2 = await asyncPromise2(result1);const result3 = await asyncPromise3(result2);const result4 = await asyncPromise4(result3);console.log(result4);
尽量避免直接返回 await ,特别是在需要 try..catch 的时候:
// ❌async () => { try { return await getUser(userId); } catch (error) { // 输出错误 }}// ✅async () => { try { const user = await getUser(userId); return user; } catch (error) { // 输出错误 }}
// ❌Promise.reject('这是一个错误');// ✅Promise.reject(new Error('这是一个错误'));
本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-83620-0.html不要在循环await啦,异步操作的六个最佳实践!
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 要么返回错误值,要么输出日志,别两样都做