#javascript #asynchronous
#javascript #асинхронный
Вопрос:
Рассмотрим два приведенных ниже фрагмента:
const loop1NoPromise = () => {
let i = 0
for (i; i < 500000; i ) {}
}
const loop2NoPromise = () => {
let i = 0
for (i; i < 500000; i ) {}
}
const startNoPromise = () => {
console.time('No promise')
loop1NoPromise()
loop2NoPromise()
console.timeEnd('No promise')
}
startNoPromise()
const loop1Promise = async () => {
let i = 0
for (i; i < 500000; i ) {}
return new Promise((resolve) => resolve());
}
const loop2Promise = async () => {
let i = 0
for (i; i < 500000; i ) {}
return new Promise((resolve) => resolve());
}
const startPromise = async () => {
console.time('With promise')
await Promise.all([loop1Promise(), loop2Promise()])
console.timeEnd('With promise')
}
startPromise()
Мне было интересно, может ли делегирование нескольких функций, которые не предназначались Promise
для использования, веб-API-интерфейсам браузера, а затем await
их редактирование каким-либо образом повысить производительность. Приступая к этому эксперименту, я наполовину ожидал startPromise
, что они будут работать немного быстрее, startNoPromise
а другая половина меня ожидала, что они будут выполняться / — одинаково.
Однако выполнение приведенных ниже фрагментов по отдельности показывает, что startNoPromise
это значительно быстрее, чем startPromise
. Что для меня странно, так это то, что если я объединю эти два фрагмента в один фрагмент, а затем выполню startNoPromise
и startPromise
, тогда они будут выполняться более или менее одинаково быстро… но при их индивидуальном запуске разница во времени составляет ~ 1 мс, при startNoPromise
этом тактовая частота постоянно составляет около 2,245 мс.
Мой вопрос в том, почему моя первоначальная логика была ошибочной, что превращение функций, не связанных с обещаниями, в promises и передача их на аутсорсинг веб-API заставили бы их работать быстрее (потому что поэтому они будут выполняться асинхронно)? Кроме того, почему Promise
версия этих двух функций выполняется с меньшей скоростью, чем их синхронные аналоги?
Комментарии:
1. Асинхронные функции используют совместную многозадачность . Они не выполняются параллельно . Они не могут. Одновременно может выполняться только одна вещь. Ваши два цикла не уступают друг другу; первый, который запускается, выполняется до завершения, а затем запускается другой. Что ничем не отличается от кода синхронизации, за исключением того, что у него есть некоторые дополнительные накладные расходы.
2. я бы скорее сказал, что ваш код выполняется «с задержкой», а не «асинхронно».
3. исследуйте веб-работников
Ответ №1:
«Проблема» с JavaScript заключается в том, что все выполняется в одном потоке, т. Е. Одновременно можно выполнить только одну вещь. Использование promises для проблем, связанных с процессором (код, ограниченный мощностью процессора), на самом деле замедлит его. Причина замедления заключается в том, что вызовы API для обещаний и управление обещаниями также требуют затрат процессора.
Еще одна вещь, которую следует отметить, это то, что с функциями, связанными с процессором, без каких-либо ожиданий, эти функции будут выполняться последовательно (одна за другой) в любом случае. С другой стороны, добавление await сделает его еще медленнее, поскольку будет больше накладных расходов на управление.
Обещания отлично подходят для кода, где вам приходится ждать завершения чего-либо вне основного процесса. Чаще всего это будет ввод-вывод.
Ответ №2:
Оба фрагмента являются синхронными вычислениями.
Возврат обещания не делает предыдущие вычисления «асинхронными»: он просто возвращает объект, представляющий асинхронный результат. Это (в данном случае уже решенное) обещание.
В вашем втором сокращенном коде добавляемый вами код только обертывает результат в обещание, разрешение которого не может быть обработано до следующего цикла цикла событий.
Другими словами: когда вы это делаете await Promise.all(...)
, вы сообщаете движку JS, чтобы он посещал все ожидающие события и в следующем цикле проверял, разрешены ли все обещания, и получал их значение или продолжал ждать в противном случае и так далее.
Если вы удалите ключевое слово await, вы увидите почти идентичные результаты.
Вы также можете обернуть Promise.all(...)
выражение в a console.log(...)
, и вы увидите это значение (ожидающее обещание).