使用Axios克服待解决的承诺并在Node.js中完成JSON的构建

时间:2018-11-02 01:47:53

标签: javascript node.js json promise axios

我正在尝试通过使用JSON连续创建HTTP requests来构建Axios文件:

  1. 获取对象(项目)的数组
  2. 在每个名为task的项目中创建一个数组属性
  3. 获取每个项目的任务
  4. 将每个项目的任务推入其task属性(即,在每个项目对象中填充该数组)
  5. 从修改后的项目数组中创建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并最终添加丢失的数据。

我需要做什么?

2 个答案:

答案 0 :(得分:1)

问题在于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处理程序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链接到输入并再次输出的末尾并没有任何用处-可以完全将其保留。

答案 1 :(得分:0)

您可以尝试使用async await语法来编写异步代码,例如使用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 || [];
}