Я пытаюсь создать JSON
файл, выполнив последовательные HTTP requests
с помощью Axios
:
JSON
из модифицированного массива проектовКод:
let getProjects = function() {
try {
return axios.get('https://app.asana.com/api/1.0/projects/').then(response => { return response } )
} catch (error) {
console.error(error)
}
}
let getTasks = function(project) {
try {
return axios.get('https://app.asana.com/api/1.0/projects/'+project+'/tasks').then(response => { return response } )
} catch (error) {
console.error(error)
}
}
function getAsanaData() {
return getProjects()
.then(function(result) {
let projects = []
for(let project of result.data.data){
project.tasks = []
project.tasks.push(getTasks(project.gid))
projects.push(project)
}
return projects;
})
}
Promise.try(() => {
return getAsanaData();
}).then((result) => {
console.log(util.inspect(result, {showHidden: false, depth: null}))
var asanaData = JSON.stringify(result);
fs.writeFile("thing.json", asanaData);
});
Результат журнала выглядит примерно так:
[ { id: 35534235917762,
gid: '35534235917762',
name: 'History+',
resource_type: 'project',
tasks: [ Promise { <pending> } ] },
{ id: 35583453238038,
gid: '35583453238038',
name: 'NRG - AccountingSeed Phase 2',
resource_type: 'project',
tasks: [ Promise { <pending> } ] },
]
Обратите внимание на сохранение Promise { <pending> }
.
JSON - это что-то вроде этого:
[
{
"id": 35534235917762,
"gid": "35534235917762",
"name": "History+",
"resource_type": "project",
"tasks": [
{}
]
},
{
"id": 35583453238038,
"gid": "35583453238038",
"name": "NRG - AccountingSeed Phase 2",
"resource_type": "project",
"tasks": [
{}
]
}
]
Обратите внимание на свойства пустых задач.
Кажется, я очень близок к достижению полного JSON
, но я потратил много часов, пытаясь преодолеть ожидающее promise
и, наконец, добавить недостающие данные.
Что мне нужно сделать?
Вы можете попробовать асинхронное ожидание синтаксиса для написания асинхронного кода, например, синхронного с использованием обещаний. Это может быть просто понять и выполнить обещание. пример:
Мы могли бы перезаписать функцию getProject следующим образом:
let getProjects = async function() {
let projectsResponse;
try {
projectsResponse =
axios.get('https://app.asana.com/api/1.0/projects/');
} catch (error) {
console.error(error)
}
return projectsResponse && projectsResponse.data || [];
}
Проблема в том, что getTasks
является асинхронным, поэтому просто вызов getTasks
в цикле for
не будет ждать решения Promises. Чтобы дождаться, когда все они будут разрешены, используйте Promise.all
в массиве этих обещаний, а затем, когда это будет разрешено, вы можете назначить результат project.tasks
:
function getAsanaData() {
return getProjects()
.then((result) => {
const projects = result.data.data;
const taskPromises = projects.map((project) => {
return getTasks(project.gid)
.then((task) => {
project.tasks = [task];
});
});
return Promise.all(taskPromises)
.then(() => projects);
});
}
Также обратите внимание, что отклоненное Promise
не будет зажато внутри блока try
/catch
:
try {
new Promise((_, reject) => setTimeout(reject, 1000))
} catch(e) {
console.log('error caught');
}
Вместо try/catch
правильный способ ловить ошибки Promise
(когда вы не используете await
) - это .catch
обработчика .catch
в конце цепочки Promise
:
const getProjects = function() {
return axios.get('https://app.asana.com/api/1.0/projects/')
.catch((error) => console.error(error));
}
Но .catch
приводит к разрешению цепочки Promise
, а не к отказу, что означает, что при вызове функции результирующее Promise
будет решать значение (undefined
), а не отклонять, что, вероятно, не то, что вы хотите - вы можете найти поток управления легче обрабатывать, если вы поймаете ошибки в вызывающем элементе функции:
return Promise.all(taskPromises)
.then(() => projects);
.catch((err) => {
console.log(err);
});
Что - то еще отметить, что .then
, такие как
.then(response => { return response } )
полностью лишнее - существующее Promise
уже решает response
. Помещение другого Promise
в конец, которое берет вход и выводит его снова, ничего полезного не делает - не стесняйтесь полностью отказаться от этого.