【问题标题】:Retry promise until resolved (Too much recursion error)重试承诺直到解决(递归错误太多)
【发布时间】:2019-01-18 13:02:06
【问题描述】:

我试图测试是否可以在解决之前进行承诺重试,但它一直给出“递归过多”错误,我不明白为什么它在第三次递归后没有停止。

以下代码试图模拟对服务器的失败查询请求,该请求来自非承诺函数。

function nonPromiseCallback(x, resolve, reject){    
  if(x < 3){
    reject(x)
  }else{
    resolve(x)
  }
}

function tryUntilThree(x){
  return new Promise( (resolve, reject) => {
    nonPromiseCallback(x, resolve, tryUntilThree(x+1));
  })
}

tryUntilThree(1)
.then(console.log);

【问题讨论】:

  • 检查this的答案,可能对你有帮助
  • 你得到了太多的递归,因为 tryUntilThree 被调用了太多次。请注意,您已经编写了 tryUntilThree(x+1),即引擎必须先解析对 tryUntilThree 的调用,然后才能调用 nonPromiseCallback。你在那里有一个无限循环。
  • @some:介意我在回答中引用您的评论吗? :)
  • @vicbyte 我不介意。我在代码周围添加了特殊引号(在我的评论中他们用斜体表示)

标签: javascript ecmascript-6 es6-promise


【解决方案1】:

由于您对 Promise 失败感兴趣,您可以使用 catch 处理程序。

至于你的代码为什么不起作用,some 有一个很好的解释(也在评论中):

因为tryUntilThree 被调用了太多,所以你得到了太多的递归 次。注意你写了tryUntilThree(x+1),即引擎 必须先解决对tryUntilThree 的调用,然后才能调用 nonPromiseCallback。你在那里有一个无限循环。

function nonPromiseCallback(x, resolve, reject){    
  if(x < 3){
    reject(x)
  }else{
    resolve(x)
  }
}

function tryUntilThree(x){
  return new Promise( (resolve, reject) => 
    nonPromiseCallback(x, resolve, reject)
  ).catch(() => 
    tryUntilThree(x + 1)
  )
}

tryUntilThree(1)
.then(console.log);

【讨论】:

    【解决方案2】:

    问题在于nonPromiseCallback 方法调用,而不是函数引用,而是传递一个实际函数,然后调用该函数。

    问题:

    nonPromiseCallback(x, resolve, tryUntilThree(x+1));
    

    修复:

    nonPromiseCallback(x, resolve, tryUntilThree);
    

    reject(x+1);
    

    【讨论】:

    • @Bergi 我指出了他所面临的调用堆栈问题的修复(无限递归),我没有指出其他任何事情,因为我不知道他想要从代码中得到什么。
    【解决方案3】:

    我尝试了您的代码,但得到了TypeError: reject is not a function。 那是因为你传入了tryUntilThree(x+1),它会在传递给nonPromiseCallback之前执行函数。

    所以我想出了这段代码,试图完成你想要的。

    let res;    // used for keeping a reference to the original resolve
    function nonPromiseCallback(x, resolve, reject){
        if(x < 3){
          reject(x + 1);
        }
        else{
          resolve(x);
        }
    }
    
    function tryUntilThree(x){
        return new Promise((resolve) => {
            if(!res){
                res = resolve;
            }
            nonPromiseCallback(x, res, tryUntilThree);
        });
    }
    
    tryUntilThree(1)
    .then(res => console.log("RESULT:", res));
    

    let res;,该变量用于保持对原始解析的引用,以便.then执行。

    【讨论】:

      【解决方案4】:

      正如我在评论中所说,对于你的问题,你有一个无限循环,因为调用nonPromiseCallback 需要tryUntilThree 的结果......为了得到这个,tryUntilThree 被调用......并且它一直在循环,直到内存耗尽或宇宙终结,以先到者为准。

      您需要进行两项更改:

      function nonPromiseCallback(x, resolve, reject){
        if(x < 3){
          reject(x+1) // the increment of x is moved to here.
        }else{
          resolve(x)
        }
      }
      
      function tryUntilThree(x){
        return new Promise( (resolve, reject) => {
          nonPromiseCallback(x, resolve, tryUntilThree); // Just pass the function, it will be called later
        })
      }
      
      tryUntilThree(1)
      .then(console.log);
      

      如果您可以使用asyncawait(2017 年以来的新功能),您可以这样解决(我将最大尝试次数的决定移至调用函数):

      function nonPromiseCallback(x, resolve, reject){
        if(x < 3){
          reject(x+1)
        }else{
          resolve(x)
        }
      }
      
      async function tryUntilThree(){
        const maxAttempts = 3;
        let attempt = 1;
      
        do {
          try {
            // "await" waits for the prommise to resolve or reject.
            // If it is rejected, an error will be thrown. That's why
            // this part of the code is inside a try/catch-block.
            const result = await new Promise( (resolve, reject) =>
              nonPromiseCallback( attempt, resolve, reject )
            );
            return result; // Return the result from nonPromiseCallback
          }
          catch (error) {
            // The nonPromiseCallback failed. Try again
            attempt += 1;
          }
        } while ( attempt <= maxAttempts );
      
        // Signal error after all retires.
        throw Error(`Failure, even after ${maxAttempts} tries`);
      }
      
      tryUntilThree()
      .then(console.log);
      

      【讨论】:

        猜你喜欢
        • 2016-12-23
        • 2018-05-28
        • 2015-12-08
        • 2021-01-25
        • 2021-08-19
        • 1970-01-01
        • 1970-01-01
        • 2019-08-21
        • 1970-01-01
        相关资源
        最近更新 更多