В чем разница между return undefined и return Promise.resolve () в асинхронной функции? - PullRequest
0 голосов
/ 12 декабря 2018

Привет, ребята ~ Я нашел интересную вещь с возвращаемым значением асинхронной функции.

Есть два кода:

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 () в асинхронной функции?

1 Ответ

0 голосов
/ 12 декабря 2018

Они оба возвращают одно и то же, только в разное время цикла событий.

Ссылка на спецификацию: ( Запустите фрагмент кода, чтобы увидеть раздел спецификации. )

Как видно, на шаге 3.d.1 Обещание разрешенонемедленно (как указано в шаге 3.b) Утверждение: если мы вернемся сюда . (Как и в первом примере)

С другой стороны, когда возвращается Обещание, последовательность продолжается допосле выполнения шага 7 запускается AsyncFunctionAwait (25.5.5.3) и, наконец, на шаге 8 возвращается (как и во втором примере)

Вот ссылка из спецификации: https://www.ecma -international.org / ecma-262 / 8.0 / # sec-async-functions-abstract-operations-async-function-start .

<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 !&nbsp;
                <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 !&nbsp;
                <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 !&nbsp;
                <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>
...