大家好,我发现了一个有趣的东西,它带有异步函数的返回值。
有两个代码:
async function test () {
return Promise.resolve(undefined)
}
async function test () {
return undefined
}
那么它们之间有什么区别?
如果您像我一样说“它们是同一件事”,那么我对以下代码感到困惑:
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log('async2 start');
// return Promise.resolve();
}
async1();
new Promise(function (resolve) {
console.log("Promise 1 start");
resolve();
}).then(function () {
console.log("Then 1");
}).then(function () {
console.log("Then 2");
}).then(function () {
console.log("Then 3");
}).then(function () {
console.log("Then 4");
});
在Chrome 73中,您将获得:
async1 start
async2 start
Promise 1 start
async1 end
Then 1
Then 2
Then 3
Then 4
现在,如果我们return Promise.resolve()
在async2函数中:
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log('async2 start');
return Promise.resolve();
}
async1();
new Promise(function (resolve) {
console.log("Promise 1 start");
resolve();
}).then(function () {
console.log("Then 1");
}).then(function () {
console.log("Then 2");
}).then(function () {
console.log("Then 3");
}).then(function () {
console.log("Then 4");
});
在Chrome 73中,您将获得:
async1 start
async2 start
Promise 1 start
Then 1
Then 2
async1 end
Then 3
Then 4
令人惊讶?请注意,async1 end
与第一种情况不同,只是因为我们return Promise.resolve()
在async2函数中。
顺便说一句,Chrome 70中的代码与Chrome 73不同。
您将获得Chrome 70中的第一个
async1 start
async2 start
Promise 1 start
Then 1
Then 2
async1 end
Then 3
Then 4
然后您将获得Chrome 70中的第二个
async1 start
async2 start
Promise 1 start
Then 1
Then 2
Then 3
async1 end
Then 4
Chrome 70和73之间的差异可能是此博客中的原因: https://v8.dev/blog/fast-async
因此,Chrome 73在将来似乎是正确的行为。但是我仍然很困惑,异步函数中return undefined和return Promise.resolve()之间有什么区别?
答案 0 :(得分:0)
它们都在事件循环的不同时间返回完全相同的东西。
参考规范:(运行代码段以查看规范部分。)
如您所见,在步骤3.d.1中,该诺言立即得到解决(如步骤3.b.所述:声明:如果我们返回此处。(如您的第一个示例所示)< / p>
另一方面,当返回Promise时,该序列继续进行,直到步骤7运行AsyncFunctionAwait
(25.5.5.3)之后,最后返回步骤8。 (就像您的第二个示例一样)
<emu-clause id="sec-async-functions-abstract-operations-async-function-start" aoid="AsyncFunctionStart">
<h1><span class="secnum">25.5.5.2</span>AsyncFunctionStart ( <var>promiseCapability</var>, <var>asyncFunctionBody</var> )</h1>
<emu-alg>
<ol>
<li>Let <var>runningContext</var> be the
<emu-xref href="#running-execution-context" id="_ref_6309"><a href="#running-execution-context">running execution context</a></emu-xref>.</li>
<li>Let <var>asyncContext</var> be a copy of <var>runningContext</var>.</li>
<li>Set the code evaluation state of <var>asyncContext</var> such that when evaluation is resumed for that
<emu-xref href="#sec-execution-contexts" id="_ref_6310"><a href="#sec-execution-contexts">execution context</a></emu-xref> the following steps will be performed:
<ol type="a">
<li>Let <var>result</var> be the result of evaluating <var>asyncFunctionBody</var>.</li>
<li>Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done.</li>
<li>Remove <var>asyncContext</var> from the
<emu-xref href="#execution-context-stack" id="_ref_6311"><a href="#execution-context-stack">execution context stack</a></emu-xref> and restore the
<emu-xref href="#sec-execution-contexts" id="_ref_6312"><a href="#sec-execution-contexts">execution context</a></emu-xref> that is at the top of the
<emu-xref href="#execution-context-stack" id="_ref_6313"><a href="#execution-context-stack">execution context stack</a></emu-xref> as the
<emu-xref href="#running-execution-context" id="_ref_6314"><a href="#running-execution-context">running execution context</a></emu-xref>.</li>
<li>If <var>result</var>.[[Type]] is
<emu-const>normal</emu-const>, then
<ol>
<li>Perform !
<emu-xref aoid="Call" id="_ref_6315"><a href="#sec-call">Call</a></emu-xref>(<var>promiseCapability</var>.[[Resolve]],
<emu-val>undefined</emu-val>, «
<emu-val>undefined</emu-val>»).</li>
</ol>
</li>
<li>Else if <var>result</var>.[[Type]] is
<emu-const>return</emu-const>, then
<ol>
<li>Perform !
<emu-xref aoid="Call" id="_ref_6316"><a href="#sec-call">Call</a></emu-xref>(<var>promiseCapability</var>.[[Resolve]],
<emu-val>undefined</emu-val>, «<var>result</var>.[[Value]]»).</li>
</ol>
</li>
<li>Else,
<ol>
<li>Assert: <var>result</var>.[[Type]] is
<emu-const>throw</emu-const>.</li>
<li>Perform !
<emu-xref aoid="Call" id="_ref_6317"><a href="#sec-call">Call</a></emu-xref>(<var>promiseCapability</var>.[[Reject]],
<emu-val>undefined</emu-val>, «<var>result</var>.[[Value]]»).</li>
</ol>
</li>
<li>Return.</li>
</ol>
</li>
<li>Push <var>asyncContext</var> onto the
<emu-xref href="#execution-context-stack" id="_ref_6318"><a href="#execution-context-stack">execution context stack</a></emu-xref>; <var>asyncContext</var> is now the
<emu-xref href="#running-execution-context" id="_ref_6319"><a href="#running-execution-context">running execution context</a></emu-xref>.</li>
<li>Resume the suspended evaluation of <var>asyncContext</var>. Let <var>result</var> be the value returned by the resumed computation.</li>
<li>Assert: When we return here, <var>asyncContext</var> has already been removed from the
<emu-xref href="#execution-context-stack" id="_ref_6320"><a href="#execution-context-stack">execution context stack</a></emu-xref> and <var>runningContext</var> is the currently
<emu-xref href="#running-execution-context" id="_ref_6321"><a href="#running-execution-context">running execution context</a></emu-xref>.</li>
<li>Assert: <var>result</var> is a normal completion with a value of
<emu-val>undefined</emu-val>. The possible sources of completion values are
<emu-xref aoid="AsyncFunctionAwait" id="_ref_6322"><a href="#sec-async-functions-abstract-operations-async-function-await">AsyncFunctionAwait</a></emu-xref> or, if the async function doesn't await anything, the step 3.g above.</li>
<li>Return.
</li>
</ol>
</emu-alg>
</emu-clause>