javascriptAsync / Await并享受它的所有好处:
然而,最好不要让漂亮而干净的语法让你的思维远离并发,以及如何同时运行任务。
并发计算是一种计算形式,其中在重叠时间段期间执行多个计算 - 同时 - 而不是顺序执行(一个在下一个启动之前完成)
案例1:任务列表
假设有一个需要在外部服务上发布的帖子列表。 在发布之前,您需要验证一些帖子字段以及它们是否可以发布。
同步解决方案
您可以遍历列表并验证每个帖子,然后如果帖子有效,则继续并发布它。
async function publishAll() {
// You get the posts
const posts = await getPosts();
const successes = [];
const failures = [];
for (const post of posts) {
// synchronous check for validtion
if (!validate(post)) {
failures.push({ post, status: "failed" });
} else {
// publish it to the 3rd party api
try {
await publish(post);
results.push({ post, status: "published" });
} catch (e) {
failures.push({ post, status: "failed", error: e });
}
}
}
return {
successes,
failures
};
}
此解决方案有效,但您需要注意每个帖子必须等到上一个帖子结束才能完成。我们没有理由不同时执行所有这些。
并发解决方案
首先,我们将创建一个发布管道:validate→publish
其次,我们将所有帖子映射到管道并返回任务列表(Promises)。 现在我们可以调用“Promise.all”来等待所有管道完成。 执行时间已减少到几乎一个管道,因为每个管道彼此独立运行。
如果您要处理很长的帖子序列,最好将管道拆分成块并逐个执行。
async function publishPipeline(post){
if (!validate(post)){
return { post, status: "failed" };
}
try {
await publish(post)
return { post, status: "published" };
} catch (e) {
return { post, status: "failed", error: e };
}
}
async function publishAll() {
const posts = await getPosts();
const publishTasks = posts.map(publishPipeline);
const results = await Promise.all(publishTasks);
const successes = results.filter(post => post.status === "published");
const failures = results.filter(post => post.status === "failed");
return {
successes,
failures
};
}
案例2:独立来源
有时你会在几个独立的数据源上进行中继,就像拥有一个函数的多个参数一样。 它们不会相互阻塞,可以同时获取。
现在让我们假设您需要比较平台中所有用户的付款,发票和收据。
顺序解决方案
您可以逐个获取每个资源,然后使用它们。但是现在每个数据源只有在前一个数据源完成后才会被提取,从而导致执行时间变慢。
async function publishAll() {
const payments = await getPayments();
const invoices = await getInvoices();
const receipts = await getReceipts();
// do stuff with that
}
并发解决方案
创建3个不同的任务,并等待所有任务完成。
这里所有的呼叫都是并发的,这意味着我们现在有更快的准备时间,特别是当呼叫时间很长时。
读后感
Async / Await可以在可读性和错误处理方面给我们带来很多好处,但我们不应该忘记明智地使用这个功能,并且总是寻找可以同时处理的任务。
始终尝试考虑哪些呼叫是非阻塞的,哪些呼叫必须逐个运行。
每当你发现自己编写一个循环等待尝试弄清楚你是否可以根据调用的依赖性使用Promise.all。
网友评论