如何组织递归promise调用

How to organize a recursive promises call

本文关键字:调用 promise 递归 何组织      更新时间:2023-09-26

我使用的是Facebook图形API,它经常返回一条"未知错误"消息,我发现如果几秒钟后重试该帖子,它就不会出现问题。

此代码将调用postAsync,在收到成功响应后,它将使用新的Promise来解决此问题,否则它将增加尝试计数器并再次调用该函数。

function guaranteedPost(endpointId, wallPost, attempts){
  attempts = attempts || 0
  ++attempts
  return graph.postAsync(endpointId + '/feed', wallPost).then(function(response){
    return new Promise.resolve(response)
  }).catch(function(error){
    setTimeout(function(){    
      console.log(attempts)
      console.log(error)
      if(attempts == 2){
        return Promise.reject('Too many attempts')
      }
      else{
        return guaranteedPost(endpointId, wallPost, attempts)
      }
    }, 5000)
  });
}
guaranteedPost(endpointId, wallPost, 0).then(function(value){
  console.log(value)
})
.catch(function(error){
  console.log(error)
})

我希望能够使用这样的代码,在那里我调用guaranteedPost,并将响应或单个"尝试次数过多"错误消息记录到控制台。然而,目前我收到的输出是:

undefined
Unhandled rejection Error: Too many attempts

因此,第一个调用返回undefined,而没有错误处理的第二个调用则失败。

此外,我想在一个更大的函数的上下文中使用它,该函数可以访问前面定义的变量,因此我不想把错误和成功处理拉到它们自己的函数中。

我忍不住觉得我已经很接近了,但这是经过一两次完整的重构之后,我仍然无法完全确定。我该如何正确地设计它?

将超时逻辑拆分为一个实际的promise,并返回它。通过这样做setTimeout,您可以捕获错误并不返回任何内容,然后将一个没有任何内容的新请求排队以捕获其失败。承诺都是关于链接的。

function delay(ms){
  return new Promise(function(resolve){
    setTimeout(resolve, ms);
  });
}
function guaranteedPost(endpointId, wallPost, attempts){
  attempts = attempts || 0
  ++attempts
  return graph.postAsync(endpointId + '/feed', wallPost).then(function(response){
    return new Promise.resolve(response)
  }).catch(function(error){
    // Return a promise that waits a little bit, then tries again.
    return delay(5000).then(function(){    
      console.log(attempts)
      console.log(error)
      if(attempts == 2){
        return Promise.reject('Too many attempts')
      }
      else{
        return guaranteedPost(endpointId, wallPost, attempts)
      }
    })
  });
}

我也会把这个代码简化一点:

function delay(ms){
  return new Promise(function(resolve){
    setTimeout(resolve, ms);
  });
}

function guaranteedPost(endpointId, wallPost, attempts){
  return graph.postAsync(endpointId + '/feed', wallPost)
    .catch(function(error){
      if (attempts === 2) throw new Error('Too many attempts');
      // Return a promise that waits a little bit, then tries again.
      return delay(5000).then(function(){   
         return guaranteedPost(endpointId, wallPost, (attempts | 0) + 1);
      })
    });
}