Повторите обещание, пока оно не будет решено (слишком много ошибок рекурсии) - PullRequest
0 голосов
/ 18 января 2019

Я пытался проверить, могу ли я повторить обещание, пока оно не разрешится, но оно продолжает выдавать ошибку «слишком много рекурсии», и я не могу понять, почему оно не останавливается после 3-й рекурсии.

Следующий код пытается эмулировать неудачный запрос к серверу, который поступает из функции без обещаний.

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

Ответы [ 4 ]

0 голосов
/ 19 января 2019

Как я уже сказал в своем комментарии, к вашему вопросу у вас был бесконечный цикл, поскольку для вызова 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);

Если вы можете использовать async и await (новые функции с 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);
0 голосов
/ 18 января 2019

Я попробовал ваш код, но получил 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 выполняется.

0 голосов
/ 18 января 2019

Поскольку вас интересует ошибка обещания, вы можете использовать обработчик catch.

Что касается того, почему ваш код не работает, вот хорошее объяснение некоторыми (также в комментарии):

Вы получаете слишком много рекурсии, потому что 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);
0 голосов
/ 18 января 2019

Проблема заключается в вызове метода nonPromiseCallback, вместо ссылки на функцию, вы передаете фактическую функцию, а затем вызываете эту функцию.

Проблема:

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

Исправлено:

nonPromiseCallback(x, resolve, tryUntilThree);

и

reject(x+1);
...