使用Node.js和Promise获取分页数据

8
请记住,我刚接触 node.js,之前主要从事安卓开发。
我的情况是这样的:
1. 对数据库运行查询,返回 null 或者一个值。 2. 使用数据库中的值调用 web 服务,获取分页信息。每次调用会返回一个参数,以便下一次调用获取更多信息。 3. 获取所有项目后,将它们存储在数据库表中。 4. 如果一切正常,对于先前接收到的每个项目,我需要进行另一个 web 调用,并将检索到的信息存储在另一个表中。 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()按顺序执行操作。


1
在这里:https://stackoverflow.com/questions/44783797/nodejs-inserting-data-into-postgresql-error,您可以找到一个使用pg-promise实现异步拉取数据的事务示例。 - vitaly-t
1
你可能在事务之外使用了knex。这次更加棘手。你需要一个事务来回滚更改,并且需要运行一个无限异步序列。这就是该示例所做的。 - vitaly-t
@vitaly-t 确实,你说得对。如果在获取过程中出现问题,我需要能够回滚所有更改。你能否在这里发布与我的问题相关的答案?感谢您抽出时间来回答我的问题。 - Alin
最好阅读这个链接:https://github.com/vitaly-t/pg-promise/wiki/Data-Imports。这里重新发布太多了。 - vitaly-t
@vitaly-t 我正在查看你对另一个问题的回答和你提供的链接。我的问题是,如何处理 t.sequence(index) 中的索引?例如,在每个网络调用中,我都会得到 nextPage 值,但我不明白你如何实际调用 getNextData(index),因为我没有看到 index 被保存或发送到任何地方,因为它可能在每个 getNextData 上更改或为空。 - Alin
显示剩余5条评论
2个回答

4

是的,在第一次调用时解决承诺确实是发生了。您应该将 resolve(value) 放在 if 语句中,检查是否需要获取更多数据。您还需要重新构建逻辑,因为 node 是异步的。除非更改逻辑,否则上面的代码将无法工作。

解决方法1:

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

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); 
      }
    });
  })    
}

我还没有测试过,但是这样做应该可以解决问题。如果问题仍然存在,请在评论中告诉我。

解决方案2:

您可以删除Promise并尝试使用回调来实现相同的功能,因为它们更容易理解,并且对于熟悉结构化语言的程序员来说也更有意义。


感谢您抽出时间回复我。在您的答复中,我没有看到使用 Promise,并且这是一个请求去使用它,正如标题所说。 - Alin
1
@Alin 在我回答问题后你修改了标签。我更新了答案。我猜应该可以工作。 - vijaykrishnavanshi
我已经编辑了情景。如果可以的话,请更新您的答案。谢谢您的时间。 - Alin
我已尝试详细说明注释。请明确指出您遇到的问题,然后我可能会相应更新答案。 - vijaykrishnavanshi
一个简短的问题,为什么getList没有使用Promise?有什么原因吗? - Alin
因为它只在新的 Promise(** context **) 的上下文中被调用。它有助于根据您决定的条件解决承诺。就像输入数据并获取结果返回一样,在这种情况下获取承诺得到解决。 - vijaykrishnavanshi

1

看了你的问题,我创建了一个循环遍历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。但是它需要更多的复杂性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接