Ich habe versucht zu testen, ob ich ein Versprechen wiederholen kann, bis es behoben ist, aber es gibt immer wieder den Fehler "zu viel Rekursion" und ich kann nicht verstehen, warum es nach der dritten Rekursion nicht aufhört.

Der folgende Code versucht, eine fehlgeschlagene Abfrageanforderung an einen Server zu emulieren, der von einer nicht versprochenen Funktion stammt.

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);
0
Mojimi 18 Jän. 2019 im 16:02

4 Antworten

Beste Antwort

Da Sie an einem Versprechensfehler interessiert sind, können Sie den Catch-Handler verwenden.

Hier ist eine gute Erklärung von some (auch im Kommentar), warum Ihr Code nicht funktioniert:

Sie erhalten zu viel Rekursion, weil tryUntilThree zu viele heißt mal. Beachten Sie, dass Sie tryUntilThree(x+1) geschrieben haben, dh die Engine muss den Anruf an tryUntilThree auflösen, bevor er anrufen kann nonPromiseCallback. Sie haben dort eine Endlosschleife.

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);
3
some 19 Jän. 2019 im 01:19

Wie ich in meinem Kommentar zu Ihrer Frage sagte, hatten Sie eine Endlosschleife, da zum Aufrufen von nonPromiseCallback das Ergebnis von tryUntilThree benötigt wurde ... und um dies zu erhalten, wurde tryUntilThree aufgerufen. .. und es wurde wiederholt, bis die Erinnerung erschöpft war oder das Ende des Universums, je nachdem, was zuerst eintrat.

Sie müssen zwei Änderungen vornehmen:

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

Wenn Sie async und warten (neue Funktionen seit 2017), die Sie lösen könnten es ist so (ich habe die Entscheidung über die maximale Anzahl von Versuchen auf die aufrufende Funktion verschoben):

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);
1
some 19 Jän. 2019 im 02:01

Das Problem besteht darin, dass Sie beim Methodenaufruf nonPromiseCallback anstelle einer Funktionsreferenz eine tatsächliche Funktion übergeben und diese Funktion dann aufrufen.

Problem:

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

Fix:

nonPromiseCallback(x, resolve, tryUntilThree);

Und

reject(x+1);
1
Danyal Imran 18 Jän. 2019 im 13:36

Ich habe Ihren Code ausprobiert, aber die TypeError: reject is not a function erhalten. Dies liegt daran, dass Sie tryUntilThree(x+1) übergeben, das die Funktion ausführt, bevor Sie sie an nonPromiseCallback übergeben.

Also habe ich mir diesen Code ausgedacht, um zu versuchen, das zu erreichen, was Sie wollen.

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;, diese Variable wird verwendet, um einen Verweis auf die ursprüngliche Auflösung beizubehalten, damit .then ausgeführt wird.

1
robbannn 18 Jän. 2019 im 13:41