Порядок выполнения операций в асинхронных циклах js
Есть асинхронная функция buildDependencyTree, которая должна построить дерево зависимостей в формате объектов на основе объекта, содержащего имена корневых пакетов. Она принимает на вход этот исходный объект и асинхронную функцию fetcher, которая принимает имя пакета и возвращает список его зависимостей.
Функция использует цикл const key in object, который запрашивает список зависимостей для каждого ключа объекта (пакета), записывает элементы списка, как ключи вложенного объекта и затем рекурсивно вызывает функцию buildDependencyTree с этим новым объектом.
async function buildDependencyTree(dependenciesList, fetcher) {
//функция для запроса зависимостей пакета
async function getdependencies(package) {
return fetcher(package)
.then(response => {
return response
})
.catch(err => console.log(err))
}
//цикл, проходящий по ключам текущего объекта
for (const item in dependenciesList) {
let refToItem = dependenciesList[item] //ссылка на текущий объект(пока пустой)
let r = await getdependencies(item) //запрос зависимостей для текущего ключа
console.log(item, refToItem, r, dependenciesList, '1')
if (r.dependencies.length !== 0) { //если зависимости найдены добавляем их как ключи в объект и ставим значение {}
r.dependencies.forEach(dep => refToItem[dep] = {})
console.log(refToItem, r, dependenciesList, '2')
buildDependencyTree(refToItem, fetcher) // вызываем функцию со следующим (вложенным) объектом
}
}
return dependenciesList
}
//исходный объект с пакетами
const deps = {
"aroot": {},
"broot": {}
}
//функция задержки
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
//функция, возвращающая необходимый список зависимостей
async function fetcher(package) {
await wait(1000);
let response
switch (package) {
case "aroot":
response = {
package: 'aroot',
dependencies: ["npm", "yup"]
}
break
case "broot":
response = {
package: 'broot',
dependencies: []
}
break
case "npm":
response = {
package: 'npm',
dependencies: ["abc", "def", "ghi"]
}
break
case "yup":
response = {
package: 'yup',
dependencies: ["abc", "mno"]
}
break
case "abc":
response = {
package: 'abc',
dependencies: ["xyz"]
}
break
case "def":
response = {
package: 'def',
dependencies: []
}
break
case "ghi":
response = {
package: 'ghi',
dependencies: []
}
break
case "mno":
response = {
package: 'mno',
dependencies: []
}
break
case "xyz":
response = {
package: 'xyz',
dependencies: []
}
break
}
return response
}
//Тестовый вызов функции
buildDependencyTree(deps, fetcher)
.then(dependencyTree => console.log(dependencyTree, 'end'))
.catch(err => console.log(err.message, 'err'))
Судя по выводам в консоль, функция выводит результат после 3 вызова, до того, как обойдет все дерево (даже до того, как обойдет первую ветку зависимостей в глубину), хотя обход дерева будет продолжаться и промежуточные значения выводятся в консоль. Насколько я понял, из-за этой рассинхронизации получается неправильный ответ, но могут быть и другие ошибки. Подскажите, как сделать, чтобы результат выводился после всех итераций.
Ответы (1 шт):
buildDependencyTree(refToItem, fetcher) // вызываем функцию со следующим
В этом месте происходит вызов асинхронной функции, но не ожидается ответ.