使用 node.js 并承诺获取分页数据

Using node.js and promise to fetch paginated data

请记住,我是 node.js 的新手,我习惯于 android 开发。

我的场景是这样的:

  1. 运行 对数据库的查询 returns 为空或值
  2. 调用具有该数据库值的 Web 服务,它提供分页信息,这意味着在调用时,如果有更多信息要获取,我将获得一个参数传递给下一次调用。
  3. 检索所有项目后,将它们存储在数据库中table
  4. 如果一切顺利,对于之前收到的每个项目,我需要进行另一个网络调用并将检索到的信息存储在另一个 table
  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() 来按顺序执行操作。

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

解决方案 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:

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

考虑到您的问题,我创建了一个循环遍历 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。然而,它需要更多的复杂性。