async/await 如何以串行和并行方式工作?
Posted
技术标签:
【中文标题】async/await 如何以串行和并行方式工作?【英文标题】:How is async/await working in serial and parallel? 【发布时间】:2018-01-10 18:30:47 【问题描述】:我有两个async
函数。他们都在等待两个 3 秒的函数调用。但是第二个比第一个快。我认为更快的一个是并行运行,另一个是串行运行。我的假设正确吗?如果是,为什么会发生这种情况,因为这两个函数在逻辑上看起来都是一样的?
function sleep()
return new Promise(resolve =>
setTimeout(resolve, 3000);
);
async function serial()
await sleep();
await sleep();
async function parallel()
var a = sleep();
var b = sleep();
await a;
await b;
serial().then(() =>
console.log("6 seconds over");
);
parallel().then(() =>
console.log("3 seconds over");
);
【问题讨论】:
@Mjh Errm,setTimeout
本质上是异步的……而且 OP 代码中的几乎所有其他内容也是异步的……
@Frxstrem 除了setTimeout
根本不是异步的。它是一个同步函数,告诉事件循环稍后执行一个函数。这是一个机制,在这段代码中绝对没有异步。哪两个运动部件在不同的执行环境中以不同的速度运动?零。因此,这段代码根本不是异步的。
@Mjh 主上下文,setTimeout
的回调,serial
和 parallel
,以及对 .then
的两个调用的回调,都在不同的执行上下文中运行。跨度>
@Frxstrem 这一切都在同一个线程中工作,执行上下文没有什么不同,没有两个移动部分,有问题的函数setTimeout
是同步的。模拟异步行为的机制并不意味着某些东西是异步的。但是,嘿,如果你愿意相信它是 - 我只是一个凡人,告诉你一个你不喜欢的故事。
@Vadakkumpadath 不管怎样震撼你的世界,如果你无法区分通过事件循环通知线程和实际异步操作的 机制 之间的区别,那么好的,非常好,让我们在 javascript 世界中实现异步 :)
【参考方案1】:
Frxstream 已经有an excellent answer。以此为基础,并提供一些观点:
首先要认识到,Promise 是“热”创建的——也就是说,当您拥有一个 Promise 对象时,它已经“进行中”了。
第二个重要概念是await
类似于“异步等待”——也就是说,它暂停函数的执行,直到该承诺完成。
因此,serial
函数调用sleep
,返回一个承诺,然后(异步)等待该承诺完成。 3 秒后该承诺完成后,serial
再次调用sleep
,得到一个承诺,然后(异步)等待该承诺完成。该承诺在 3 秒后完成后,serial
完成。
parallel
函数调用sleep
并将其promise 存储在a
中,然后调用sleep
并将其promise 存储在b
中,然后(异步)等待a
完成。在a
3 秒后完成后,parallel
(异步)等待b
完成。在b
几乎立即完成后,parallel
完成。
【讨论】:
【参考方案2】:如果您像这样编写serial
函数会更清楚:
async function serial()
var a = sleep(); //
await a; // await sleep();
var b = sleep(); //
await b; // await sleep();
async function parallel()
var a = sleep();
var b = sleep();
await a;
await b;
这里你可以清楚地看到,在serial
函数中,第二个sleep()
只在第一个sleep()
完成后调用,而在parallel
中,它在第一个完成之前立即调用,然后它等待两者都完成。因此,虽然它们可能看起来在功能上相同,但它们有细微的不同。
【讨论】:
介意你从这个问题的角度看一下:***.com/q/46889290/919480 ? @cogitoergosum - 我认为 Frxstrem 只是在解释您在问题中提出的不同之处,而不是建议您必须这样做。如果您希望操作连续运行(一个接一个),上面的serial
很好。上面的parallel
确实可以更好地实现为await Promise.all([sleep(), sleep()]);
,但同样,我认为这不是上面答案的重点。上面的答案(我认为)的重点是解释问题的时间差异。
另外,var a = sleep(); var b = sleep(); await a; await b;
也一样。【参考方案3】:
因为sleep()
函数是一个同步函数,它只是返回一个异步promise,例如:
function sleep (time)
return new Promise((resolve) => setTimeout(resolve, time));
在parallel()
中,两个sleep()
同步初始化两个promise,同时等待resolve,大概3s左右。
但是,在serial()
中,两个await sleep()
意味着第二个sleep()
承诺必须等待第一个sleep()
被解析,所以大约需要6s。
【讨论】:
【参考方案4】:串行运行:一个接一个地运行函数
// ? It’s slow! and use only for serial(one after another) run
async function doThings()
const thing1 = await asyncThing1(); // waits until resolved/rejected
console.log(thing1);
const thing2 = await asyncThing2(); // starts only after asyncThing1() has finished.
console.log(thing2);
doThings();
并行运行:并行运行函数
// ✅ async code is run in parallel!
async function doThings()
const p1 = asyncThing1(); // runs parallel
const p2 = asyncThing2(); // runs parallel
// Method 1: Prefer => Promise.all()
const [resultThing1, resultThing2] = await Promise.all([p1, p2]); // waits for all
// the promises get resolved or fails fast (If one of the promises supplied to it
// rejects, then the entire thing rejects).
// Method 2: Not-Preferred
const resultThing1 = await p1;
const resultThing2 = await p2;
console.log(resultThing1); // reaches here only after both the p1 & p2 have completed.
console.log(resultThing2);
doThings();
【讨论】:
以上是关于async/await 如何以串行和并行方式工作?的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 工作原理之四-事件循环及异步编程的出现和 5 种更好的 async/await 编程方式(译)