【问题标题】:Node.js - Promise not resolving within loopNode.js - 承诺不在循环内解决
【发布时间】:2021-07-09 21:52:27
【问题描述】:

大家好,

我正在使用 Axios for Node.js 从 PipeDrive 的 API 中提取一些数据。 PipeDrive 开发 API 分页的方式有点不同。以下是他们的分页指示器的外观:

    "additional_data": {
    "pagination": {
        "start": 0,
        "limit": 100,
        "more_items_in_collection": true,
        "next_start": 100
    }
}

我需要遍历所有页面以提取数据,我的代码已成功完成此操作,但由于某种原因我无法得到解决的承诺。

我在代码中的逻辑如下:

if(more_items_in_collection){Add current page's data then re-run the same function with the next_start as a parameter}
else{Add current page's data then RESOLVE the promise to complete the function}

但即使我的代码有效(奇怪),这种解决方案也永远不会发生。

大师,您能否看看我的代码,让我知道您为什么认为它无法解决(function().then((result) => {OUTPUT}) 永远不会返回)?

一如既往的感谢!

 const queryPipeDrive = (start) =>{
 // Query is a full then-able Async function
 return new Promise((resolve, reject) => {
     // API CALL
     axios({
         method: 'GET', 
         url: pipeDriveURI, 
         params: {
             api_token: apiKey, 
             start: start
         }
     })
     // THEN DO THIS
     .then((response) => {
         // IF there are more items in collection on additional pages, iterate through the pages
         if(response.data.additional_data.pagination.more_items_in_collection){
             // Add all deals on page to the container
             for (const deal of response.data.data) {
                 db.get('deals').push(deal) // Push deal data to the StormDB File
             }
             
             console.log(chalk.cyan(`${response.data.additional_data.pagination.next_start}`))
             // Function loop created. We will loop UNTIL the 'more_items_in_collection' prop is false, then we'll resolve the promise. 
             queryPipeDrive(response.data.additional_data.pagination.next_start)

         }else{
             // Add all deals on this page to the reponse container
             for (const deal of response.data.data) {
                 db.get('deals').push(deal)
             }
             db.save() // Save changes to temp DB
             resolve(response.data.data) // Resolve Promise with the data from the successful call
         }
     })
     .catch((err) => {
         console.log(chalk.red(err))
         reject(err)
     })
 })

}

【问题讨论】:

  • queryPipeDrive( -> return queryPipeDrive(
  • @Keith 这绝对是在正确的轨道上,但返回承诺是不够的,因为他们已经将此代码包装在一个额外的承诺中
  • @NicholasTower 是的,刚去煮咖啡,我走了,我记得他也使用了一个 Promise 构造函数,即将更新。
  • @Mulan,只需阅读此内容,就完全有道理。我确实学习了 return new Promise 路线,但现在我理解了这个概念,返回一个实际的 Promise 而不是将所有东西都打包在一起更有意义!谢谢!

标签: javascript node.js promise es6-promise


【解决方案1】:

您的 more_items_in_collection 案例永远不会解决承诺。它只是创建一个新的,然后什么都不做。

此外,使用new Promise 会使您的代码变得比需要的更复杂。 Axios 已经返回了一个 Promise,所以不需要显式地创建一个新的 Promise。调用 .then 会自动创建一个新的 Promise,它会解析为你在回调中返回的任何值。

const queryPipeDrive = (start) => {
  // API CALL
  return axios({
    method: "GET",
    url: pipeDriveURI,
    params: {
      api_token: apiKey,
      start: start,
    },
  })
    // THEN DO THIS
    .then((response) => {
      // IF there are more items in collection on additional pages, iterate through the pages
      if (response.data.additional_data.pagination.more_items_in_collection) {
        // Add all deals on page to the container
        for (const deal of response.data.data) {
          db.get("deals").push(deal); // Push deal data to the StormDB File
        }

        console.log(
          chalk.cyan(`${response.data.additional_data.pagination.next_start}`)
        );
        // Function loop created. We will loop UNTIL the 'more_items_in_collection' prop is false, then we'll resolve the promise.
        return queryPipeDrive(
          response.data.additional_data.pagination.next_start
        );
      } else {
        // Add all deals on this page to the reponse container
        for (const deal of response.data.data) {
          db.get("deals").push(deal);
        }
        db.save(); // Save changes to temp DB
        return response.data.data;
      }
    })
    .catch((err) => {
      console.log(chalk.red(err));
      throw err;
    });
};

【讨论】:

  • 哇,这很有意义!我只需要了解一件事,希望你能帮助我理解它:我需要这个函数是 Then-able,这样我就可以在这个函数成功完成后运行更多代码。如果不将整个函数包装在一个 Promise 中,这可能吗?
  • 然后可以的。 axios 返回一个 Promise,在 Promise 上调用 .then.catch 也会返回一个 Promise。你只需要返回我在示例的第 2 行所做的承诺。
  • 你真是个天才!非常感谢!这很好用!它真的帮助我理解了 Promises!
【解决方案2】:

除了接受的答案。

你会考虑在 await 中使用这个异步函数吗?这样,你就调用了main()

const main = async start => {
  const res = await queryPipeDrive(start);
  if (res.isMoreItems === true) {
    await main(res.nextStart);
  }
};

async function queryPipeDrive(start) {
  const response = await axios({
    method: "GET",
    url: pipeDriveURI,
    params: {
      api_token: apiKey,
      start: start,
    },
  });

  for (const deal of response.data.data) {
    db.get("deals").push(deal);
  }

  if (response.data.additional_data.pagination.more_items_in_collection) {
    console.log(
      chalk.cyan(`${response.data.additional_data.pagination.next_start}`)
    );
    return {
      isMoreItems: true,
      nextStart: response.data.additional_data.pagination.next_start,
    };
  } else {
    db.save(); // Save changes to temp DB
    return {
      isMoreItems: false,
    };
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 2015-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多