Учитывая приведенные ниже примеры кода, есть ли разница в поведении, и если да, то каковы эти различия?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
Насколько я понимаю, в первом случае будет обработка ошибок в асинхронной функции, и ошибки будут выскакивать из обещания асинхронной функции. Однако для второго потребуется на одну галочку меньше. Это верно?
Этот фрагмент представляет собой обычную функцию, возвращающую обещание для справки.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
javascript
async-await
PitaJ
источник
источник
async
из своего второго (return promise
) образца.promise.then(() => nestedPromise)
сгладил бы и «последовал» заnestedPromise
. Интересно, чем это отличается от вложенных задач в C # там, где это нужноUnwrap
. С другой стороны, похоже, что этоawait somePromise
вызываетPromise.resolve(somePromise).then
, а не простоsomePromise.then
, с некоторыми интересными семантическими различиями.Ответы:
В большинстве случаев заметной разницы между
return
и нетreturn await
. Обе версииdelay1Second
имеют одинаковое наблюдаемое поведение (но в зависимости от реализацииreturn await
версия может использовать немного больше памяти, потому что промежуточныйPromise
может быть создан объект).Однако, как указал @PitaJ, есть один случай, когда есть разница: если
return
илиreturn await
вложено вtry
-catch
блок. Рассмотрим этот примерВ первой версии функция async ожидает отклоненного обещания, прежде чем вернуть свой результат, что приводит к тому, что отклонение превращается в исключение и
catch
достигается условие; функция, таким образом, вернет обещание, разрешающееся в строку «Сохранено!».Однако вторая версия функции возвращает отклоненное обещание напрямую, не ожидая его в асинхронной функции , что означает, что
catch
case не вызывается, и вместо этого вызывающий получает отклонение.источник
return new Promise(function(resolve, reject) { })
внутриfor...of
цикла и последующий вызовresolve()
внутри цикла после apipe()
не приостанавливают выполнение программы до тех пор, пока канал не будет завершен, как желательно, однако использованиеawait new Promise(...)
делает. последний даже действительный / правильный синтаксис? это «стенография»return await new Promise(...)
? не могли бы вы помочь мне понять, почему последнее работает, а первое - нет? для контекста, сценарий вsolution 02
из этого ответаКак упоминалось в других ответах, вероятно, есть небольшое преимущество в производительности, если вы позволите обещанию всплыть, вернув его напрямую - просто потому, что вам не нужно сначала ждать результата, а затем снова оборачивать его другим обещанием. Однако об оптимизации хвостового вызова пока никто не говорил .
Оптимизация хвостовых вызовов или «правильные хвостовые вызовы» - это метод, который интерпретатор использует для оптимизации стека вызовов. В настоящее время не многие среды выполнения поддерживают его - хотя технически это часть стандарта ES6 - но, возможно, поддержка может быть добавлена в будущем, поэтому вы можете подготовиться к этому, написав хороший код в настоящем.
В двух словах, TCO (или PTC) оптимизирует стек вызовов, не открывая новый фрейм для функции, которая напрямую возвращается другой функцией. Вместо этого он повторно использует тот же фрейм.
Поскольку
delay()
он напрямую возвращаетсяdelay1Second()
, среда выполнения, поддерживающая PTC, сначала откроет фрейм дляdelay1Second()
(внешней функции), но затем вместо открытия другого фрейма дляdelay()
(внутренней функции) будет просто повторно использовать тот же фрейм, который был открыт для внешней функции. Это оптимизирует стек, потому что может предотвратить переполнение стека (хе-хе) очень большими рекурсивными функциями, напримерfibonacci(5e+25)
. По сути, это становится петлей, которая выполняется намного быстрее.PTC доступен только тогда, когда внутренняя функция возвращается напрямую . Он не используется, когда результат функции изменяется до его возврата, например, если у вас был
return (delay(1000) || null)
, илиreturn await delay(1000)
.Но, как я уже сказал, большинство сред выполнения и браузеров еще не поддерживают PTC, поэтому, вероятно, сейчас это не имеет большого значения, но не повредит будущим требованиям вашего кода.
Подробнее читайте в этом вопросе: Node.js: есть ли оптимизации для хвостовых вызовов в асинхронных функциях?
источник
На этот вопрос сложно ответить, потому что на практике он зависит от того, как ваш транспилятор (вероятно
babel
) на самом деле отображаетasync/await
. То, что ясно независимо:Обе реализации должны вести себя одинаково, хотя у первой реализации может быть на одну меньше
Promise
в цепочке.Особенно, если вы отбросите ненужное
await
, вторая версия не потребует дополнительного кода от транспилятора, в то время как первая требует.Таким образом, с точки зрения производительности кода и отладки вторая версия предпочтительнее, хотя и очень незначительно, в то время как первая версия имеет небольшое преимущество в удобочитаемости, поскольку ясно указывает, что она возвращает обещание.
источник
undefined
), а второй возвращаетPromise
.async/await
- мне гораздо труднее рассуждать. @PitaJ верен, обе функции возвращают обещание.try-catch
? В этомreturn promise
случае ни одинrejection
не будет пойман, верно, а вreturn await promise
случае - верно?await
посетите каждый из них на каком-либо сайте вызова, результат будет совсем другим.Заметная разница: отклонение обещаний обрабатывается в разных местах.
return somePromise
передаст somePromise на сайт вызова, аawait
somePromise для урегулирования на сайте вызова (если есть). Следовательно, если somePromise отклонен, он будет обрабатываться не локальным блоком catch, а блоком catch сайта вызова.return await somePromise
сначала будет ждать обещания поселиться на месте. Следовательно, значение или исключение сначала обрабатывается локально. => Локальный блок перехвата будет выполнен, еслиsomePromise
он отклонен.Причина:
return await Promise
ждет как локально, так и снаружи,return Promise
ждет только снаружиПодробные шаги:
вернуть обещание
delay1Second()
;delay1Second()
функцияdelay(1000)
немедленно возвращает обещание с[[PromiseStatus]]: 'pending
. Назовем этоdelayPromise
.Promise.resolve()
( Источник ). Посколькуdelay1Second
это асинхронная функция, у нас есть:Promise.resolve(delayPromise)
возвращаетсяdelayPromise
, ничего не делая, потому что ввод уже является обещанием (см. MDN Promise.resolve ):await
ждет, пока неdelayPromise
будет урегулировано.delayPromise
выполняется с PromiseValue = 1:delayPromise
отклоняется:вернуться ждать обещание
delay1Second()
;delay1Second()
функцияdelay(1000)
немедленно возвращает обещание с[[PromiseStatus]]: 'pending
. Назовем этоdelayPromise
.delayPromise
не поселится.delayPromise
выполняется с PromiseValue = 1:delayPromise
отклонено:Глоссарий:
Promise.[[PromiseStatus]]
меняется сpending
наresolved
илиrejected
источник
здесь я оставляю некоторый практический код, потому что вы можете понять разницу
функция «x» - это просто асинхронная функция, чем у других функций, если она удалит возвращаемый результат, напечатает «больше кода ...»
переменная x - это просто асинхронная функция, которая, в свою очередь, имеет другую асинхронную функцию, в основной части кода мы вызываем ожидание для вызова функции переменной x, когда она завершается, она следует последовательности кода, что было бы нормально для «async / await», но внутри функции x есть другая асинхронная функция, и она возвращает обещание или возвращает «обещание», оно останется внутри функции x, забывая основной код, то есть не будет печатать "console.log (" больше кода .. "), с другой стороны, если мы поставим" await ", он будет ожидать завершения каждой функции и, наконец, следует обычной последовательности основного кода.
ниже "console.log (" finished 1 "удалите" return ", вы увидите поведение.
источник
Вот пример машинописного текста, который вы можете запустить и убедить себя, что вам нужно "return await"
источник