【问题标题】:Using node.js and promise to fetch paginated data使用 node.js 和 promise 获取分页数据
【发布时间】:2017-12-07 18:27:18
【问题描述】:

请记住,我是 node.js 的新手,我使用的是 android 开发。

我的场景是这样的:

  1. 对返回空值或值的数据库运行查询
  2. 使用该数据库值调用 Web 服务,提供分页信息,这意味着在调用时,如果有更多信息要获取,我会获得一个参数以传递给下一次调用。
  3. 检索到所有项目后,将它们存储在数据库表中
  4. 如果一切正常,对于之前收到的每件商品,我需要再次拨打网络电话并将检索到的信息存储在另一个表中
  5. 如果获取任何数据集失败,则必须从数据库中恢复所有数据

到目前为止,我已经尝试过:

getAllData: function(){
  self.getMainWebData(null)
     .then(function(result){
       //get secondary data for each result row and insert it into database
   }
}


getMainWebData: function(nextPage){
    return new Promise(function(resolve, reject) {

      module.getWebData(nextPage, function(errorReturned, response, values) {

    if (errorReturned) {
          reject(errorReturned);
        }

        nextPage = response.nextPageValue;
        resolve(values);
      })
    }).then(function(result) {

    //here I need to insert the returned values in database     

      //there's a new page, so fetch the next set of data
      if (nextPage) {
          //call again getMainWebData? 
          self.getMainWebData(nextPage)
      }

    })

从我测试的结果来看,缺少一些东西,getAllData.then 只为第一组项目触发一个,而不为其他项目触发一个,因此显然处理返回的数据不正确。

后期编辑:我已经编辑了场景。考虑到更多的研究,我的感觉是我可以使用链或.then() 来按顺序执行操作。

【问题讨论】:

  • 这里:stackoverflow.com/questions/44783797/… 你可以找到一个使用 pg-promise 异步拉取数据的事务的示例。
  • 谢谢@vitaly-t,但由于我是节点新手,我很难理解。我已经将 knex 用于 postgres 插入并且工作正常。在理解之前,我需要更详细地研究您对另一个问题的回答
  • 您可能在事务之外使用了 knex。这一次更棘手。您需要一个事务,以便能够回滚更改,并且您需要运行一个无限的异步序列。这就是该示例的作用。
  • @vitaly-t 确实,您说得有道理,好像在获取过程中发生了故障,我需要能够回滚所有更改。你能在这里发布与我的问题相关的答案吗?感谢您抽出宝贵时间回复我。
  • 最好阅读以下内容:github.com/vitaly-t/pg-promise/wiki/Data-Imports。在这里重新发布它太多了。

标签: node.js promise pg-promise


【解决方案1】:

是的,它正在发生,因为您正在解决第一次调用本身的承诺。您应该将 resolve(value) 放在 if 语句中,该语句检查是否需要获取更多数据。您还需要重构逻辑,因为节点是异步的。除非您更改逻辑,否则上述代码将不起作用。

解决方案一:

您可以将分页响应附加到您正在进行的调用上下文之外的另一个变量。稍后在您完成响应后使用该值。

getAllData: function(){
  self.getMainWebData(null)
  .then(function(result){
       // make your database transaction if result is not an error
   }
}

function getList(nextpage, result, callback){
  module.getWebData(nextPage, function(errorReturned, response, values) {
    if(errorReturned)
      callback(errorReturned);
    result.push(values);
    nextPage = response.nextPageValue;
    if(nextPage)
      getList(nextPage, result, callback);
    else
      callback(null, result);
  })
}
getMainWebData: function(nextPage){
  return new Promise(function(resolve, reject) {
    var result = [];
    getList(nextpage, result, function(err, results){
      if(err)
        reject(err);
      else{
        // Here all the items are retrieved, you can store them in a database table
        //  for each item received make your web call and store it into another variable or result set 
        // suggestion is to make the database transaction only after you have retrieved all your data 
        // other wise it will include database rollback which will depend on the database which you are using
        // after all this is done resolve the promise with the returning value
        resolve(results); 
      }
    });
  })    
}

我还没有测试过,但这样的东西应该可以工作。如果问题仍然存在,请在 cmets 中告诉我。

解决方案 2:

您可以删除 promise 并尝试使用回调做同样的事情,因为它们更容易遵循并且对熟悉结构语言的程序员来说很有意义。

【讨论】:

  • 感谢您抽出宝贵时间回复我。在你的回答中,我没有看到任何地方使用的承诺,正如标题所说,这是一个使用它的请求。
  • @Alin 你在我回答问题后更改了标签。更新了答案。我猜它应该可以工作。
  • 我已经编辑了场景。如果是这种情况,您能否更新您的答案?感谢您的宝贵时间。
  • 我已经尝试用 cmets 进行详细说明。请具体说明您遇到的问题,然后也许我会相应地更新答案?
  • 一个简短的问题,为什么 getList 不使用 Promise?有什么理由吗?
【解决方案2】:

查看您的问题,我创建了一个循环通过 Promise 的代码。 并且只有在有更多数据要获取时才会继续,存储的数据仍然可以在数组中使用。 我希望这会有所帮助。如果有帮助别忘了标记。

let fetchData = (offset = 0, limit= 10) => {
    let addresses = [...Array(100).keys()];
    return Promise.resolve(addresses.slice(offset, offset + limit))
}
// o => offset & l => limit
let o = 0, l = 10;
let results = [];
let process = p => {
  if (!p) return p;
  return p.then(data => {
    // Process with data here;
    console.log(data);
    // increment the pagination
    o += l;
    results = results.concat(data);
    // while there is data equal to limit set then fetch next page 
    // otherwise return the collected result
    return (data.length == l)? process(fetchAddress(o, l)).then(data => data) : results;
  })
}
process(fetchAddress(o, l))
.then(data => {
    // All the fetched data will be here
}).catch(err => {
// Handle Error here.
// All the retrieved data from database will be available in "results" array 
});

如果您想更频繁地执行此操作,我还创建了一个 gist 以供参考。 如果您不想使用任何全局变量,并且想以非常实用的方式进行操作。您可以查看此example。然而,它需要更多的复杂性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 2019-07-08
    相关资源
    最近更新 更多