#javascript #performance #promise #async-await #synchronization
#javascript #Производительность #обещание #async-await #синхронизация
Вопрос:
Я пытаюсь улучшить производительность кода и после нескольких лет кодирования запутался в некоторых основах. Конечно, у нас, по сути, есть вещи, которые нужно выполнять по порядку (асинхронные функции) и вещи параллельно (просто обычные синхронные функции). Я читал о обещании.примеры типов all и setTimeout и попытался создать большую функцию, переписанную со всеми этими основами, и применял асинхронность к каждой функции, и когда я закончил, это было намного медленнее, чем раньше, и теперь я понимаю, что асинхронность не так распространена, как я думал, но я в замешательстве.
Если у меня есть функция
function count(n){
let num = 0
for(let i = n; i--;){
num
}
return num
}
и добавьте, например, 140000000, тогда для завершения потребуется секунда. Если мне нужно возвращаемое значение для продолжения остальной части функции, я подумал, что мне нужно дождаться ответа, чтобы я мог использовать ответ в будущем
async function doSomething(){
const one = await count(140000000)
const two = count(one)
return two
}
async function count(n){
let num = 0
for(let i = n; i--;){
num
}
return num
}
Но на самом деле я думаю, что это не столько значение, которое мне нужно передать в следующую функцию, чтобы она работала, так что в принципе все в порядке, не ожидая ответа, потому что он в основном отправляет функцию в качестве параметра, например
async function doSomething(){
const two = count(count(140000000))
return two
}
function count(n){
let num = 0
for(let i = n; i--;){
num
}
return num
}
Аналогично задачам синхронного типа, я подумал, что мне нужно будет использовать Promise.all для ускорения работы одновременно выполняющихся функций, и функции, которые он выполняет, должны быть асинхронными, потому что он возвращает обещание таким образом, как
async function parent2(){
console.log('start')
console.time('ALL')
const numsToCount = [ 140000000, 170000000, 240000000 ]
const res = await countNums2(numsToCount)
// do other stuff with res
const fin = count(res[0])
console.timeEnd('ALL')
console.log('end', fin)
}
async function countNums2(numsToCount){
let countedNumsPromises = []
for(let i = numsToCount.length; i--;){
countedNumsPromises.push(count2(numsToCount[i]))
}
return Promise.all(countedNumsPromises)
}
async function count2(n){
let num = 0
for(let i = n; i--;){
num
}
return num
}
But then again realized I didnt really need promise.all even though its three functions that take some time but can be run together and could just do
function parent1(){
console.log('start')
console.time('ALL')
const numsToCount = [ 140000000, 170000000, 240000000 ]
const res = countNums(numsToCount)
console.timeEnd('ALL')
console.log('end', res)
}
function countNums(numsToCount){
let countedNums = []
for(let i = numsToCount.length; i--;){
countedNums.push(count(numsToCount[i]))
}
return countedNums
}
function count(n){
let num = 0
for(let i = n; i--;){
num
}
return num
}
И когда вы начинаете вкладывать такие вещи, как 3 раза, и более сложные вещи, очевидно, также сбивают с толку, но, возможно, попытка разобраться с некоторыми из этих более простых понятий поможет во всем. Нравится делать
const parents = [
{name: 'Jon', pets: ['dodo', 'goofy']},
{name: 'Tammy', pets: ['gigi', 'laffy', 'bigbird']},
{name: 'Tom', pets: ['ralphy', 'goose']},
]
const res = await Promise.all(parents.map(async parent => {
const res2 = await Promise.all(parent.pets.map(async pet => {
...
}
}
Также будет ли функция ожидания, как во многих примерах, отличаться от функции медленного подсчета?
async function doSomething(){
await Promise.all([wait(1000),wait(2000),wait(1500)])
wait(1000)
}
async function wait(ms){
return new Promise((resolve) => setTimeout(resolve, ms));
}
Так что, может быть, я много вам здесь рассказываю, но в основном, как мне реализовать синхронное программирование, а что не для правильной скорости и как правильно использовать async и promise.все против того, чтобы просто передавать все функции друг другу по мере необходимости и позволять функциям вычислять все ожидания предыдущей функции. Кроме того, я, похоже, обнаружил, что map reduce и filter, возможно, не самые быстрые, потому что вы будете перебирать одни и те же данные несколько раз, поэтому, в отличие от приведенного выше примера, я пытался придерживаться большего количества циклов for, но да, я не хочу, чтобы это отвлекало от ответа на вопрос, но это направление, в котором япытаюсь перейти.
Ответ №1:
Обещания (и, следовательно, async / await) не являются инструментом для получения синхронного кода и его ускорения. Когда вы создаете promise, это обычно потому, что вы вообще ничего не вычисляете, а вместо этого ожидаете, что произойдет что-то внешнее.
Например, вы можете ожидать возвращения сетевого ответа, или вы можете ждать истечения таймера, или ждать, пока кто-нибудь нажмет клавишу. Вы не можете выполнять какую-либо работу, пока это происходит, поэтому вместо этого вы создаете обещание, а затем прекращаете выполнение любого кода. Поскольку javascript является однопоточным, остановка выполнения вашего кода важна для запуска другого кода, включая обычный код отображения страницы в браузере.
Обещания — это объекты с .then
функцией на нем. Вы можете вызвать .then
и передать функцию, чтобы сообщить ей: «Эй, когда вы закончите ждать, пожалуйста, вызовите эту функцию». async
/ await
просто упрощает синтаксис для работы с обещаниями: async
функция автоматически создаст обещание, и await
обработка обещания автоматически вызовет .then
его.
Имея это в виду: приведенные вами примеры не имеют никакого отношения к async await. У вас есть куча синхронных вычислений, и вы не ждете ничего внешнего. Включение await в функцию map или цикл for не будет иметь никакого эффекта, кроме как запутать ваших коллег и очень незначительно увеличить время выполнения.
Комментарии:
1. Спасибо, что прояснили это, я, конечно, был смущен асинхронностью больше, чем ожидалось! Не понимал, что асинхронность не должна использоваться с внутренними обычными функциями js, но да, имеет смысл для вызовов выборки