Разница между "возвратом ждут обещания" и "возвращением обещания"

Учитывая примеры кода ниже, есть ли разница в поведении и, если да, то каковы эти различия?

return await promise

async function delay1Second() {
  return (await delay(1000));
}

return promise

async function delay1Second() {
  return delay(1000);
}

Как я понимаю, первый будет иметь обработку ошибок в функции async, и ошибки будут выходить из асинхронной функции Promise. Однако второй потребовал бы еще одного тика. Правильно ли это?

Этот фрагмент является просто общей функцией для возврата обещания для ссылки.

function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

Ответ 1

В большинстве случаев между return и return await нет заметной разницы. Обе версии delay1Second имеют одно и то же наблюдаемое поведение (но в зависимости от реализации версия return await может использовать немного больше памяти, поскольку может быть создан промежуточный объект Promise).

Однако, как отметил @PitaJ, есть один случай, когда есть разница: если return или return await вложен в блок try - catch. Рассмотрим этот пример

async function rejectionWithReturnAwait () {
  try {
    return await Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

async function rejectionWithReturn () {
  try {
    return Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

В первой версии функция async ожидает отклоненное обещание перед возвратом его результата, что приводит к тому, что отказ отклоняется в исключение и предложение catch должно быть достигнуто; функция, таким образом, вернет обещание, разрешающее строку "Сохранено!".

Однако вторая версия функции возвращает отклоненное обещание напрямую, не ожидая его в рамках функции async, что означает, что случай catch не вызывается, а вызывающий получает отказ.

Ответ 2

Это трудный вопрос для ответа, потому что на практике это зависит от того, как ваш транспилер (возможно, babel) действительно отображает async/await. То, что ясно, независимо:

  • Обе реализации должны вести себя одинаково, хотя в первой реализации может быть меньше Promise в цепочке.

  • Особенно если вы сбросите ненужный await, вторая версия не потребует дополнительного кода от транспилятора, а первая сделает.

Таким образом, из производительности кода и перспективы отладки вторая версия предпочтительнее, хотя и очень незначительно, в то время как первая версия имеет небольшую удобочитаемость, поскольку она ясно указывает, что она возвращает обещание.