Как сделать так, чтобы функция, основанная на обещаниях, выполнялась несколько раз с помощью setTimeout, прежде чем отказываться от узла 6 (то есть без спецификаций javascript для async / await) - PullRequest
0 голосов
/ 18 сентября 2018

Мне нужно получить фактическое значение из функции на основе обещаний в среде узла 6 (функции Azure), поэтому я использовал co (https://www.npmjs.com/package/co) через генераторы (вместо парадигмы async / await) для справиться с внутренним обещанием.

Мне также нужно несколько раз повторить эту функцию co / обещание, используя setTimeout, прежде чем окончательно сдаться.

В настоящее время я не могу заставить следующий код работать должным образом. Я не уверен, в чем проблема, но я не могу «уступить обещанию, возвращенному co», поэтому в конце массив, который передается вокруг рекурсивных уровней стека, содержит обещания значений (1/0) а не фактические значения.

Это оболочка для "функции, основанной на обещаниях" , которая обрабатывается с помощью try / catch , чтобы убедиться, что мы всегда возвращаем либо 1, либо 0 .

const wannabeSyncFunc = () => {
  console.log("outside co...");
  return co(function *(){
    console.log("inside co...");
    try {
      console.log("yielding...");
      // promise that could be rejected hence try/catch
      //
      // I can not change this returned promise, so I must treat it
      // as a promise that could potentially be rejected
      let stuff = yield Promise.resolve();
      console.log("stuff?", stuff);
      console.log("returning 1");
      return 1;
    } catch (err) {
      console.log("returning 0");
      return 0;
    }
    console.log("after try/catch...");
  });
}

Это рекурсивная / settimeout функция, которую нужно попробовать несколько раз, прежде чем сдаться.

const retryIntervalInMillis = 50;

const wannabeRecursiveFunc = (currTimes, attemptsArray) => {
  return co(function *(){
    console.log("Curr attemptsArray:", attemptsArray);
    console.log("Curr attemptsArray[attemptsArray.length - 1]:", attemptsArray[attemptsArray.length - 1]);
    console.log("Curr Promise.resolve(attemptsArray[attemptsArray.length - 1]):", Promise.resolve(attemptsArray[attemptsArray.length - 1]));
    if (attemptsArray[attemptsArray.length - 1] == Promise.resolve(1)) {
      console.log("Found the solution, returning straight away!")
      return attemptsArray;
    }

    if (currTimes <= 0) {
      console.log("Expired acquiring recursion");
      return attemptsArray;
    }

    currTimes--;
    const currValue = wannabeSyncFunc();
    console.log(`First: currTimes: ${currTimes} currValue: ${currValue} curr attemptsArray: ${attemptsArray}`);
    attemptsArray.push(currValue);
    if (currValue === 1) {
      return attemptsArray;
    }
    console.log(`Then: currTimes: ${currTimes} curr attemptsArray: ${attemptsArray}`);
    return yield setTimeout(wannabeRecursiveFunc, currTimes*retryIntervalInMillis, currTimes, attemptsArray);
    // return Promise.all(attemptsArray);
  });
}

Я пытался вызвать это несколькими различными способами, такими как:

const numberOfAttempts = 3;
let theArray = wannabeRecursiveFunc(numberOfAttempts, []);
console.log(">>>", theArray);

Или при условии wannabeRecursiveFunc вернуть обещание и .then после того, как обещание пытается напечатать theArray.

Я продолжаю видеть внутри массива эти элементы Promise { 1 } при его печати, но я хотел бы видеть либо 1, либо 0, поэтому Надеюсь, что эти проверки до рекурсии могли сработать, как и ожидалось . В настоящий момент эти проверки не работают, я думаю, потому что я сравниваю Promise { 1 } с 1.

Однако я не уверен, что это причина того, что все это не работает, и я даже не уверен, как это исправить. Я не уверен, нужен ли co (даже в среде node.js v6), и как заставить это обещание / setTimeout работать должным образом.

1 Ответ

0 голосов
/ 18 сентября 2018

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

Вот пара инструментов:

  1. многообещающая версия setTimeout ...

function timeoutPromise(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

timeoutPromise(1000).then(() => {
    console.log('time out expired');
});
Функция-пустышка, возвращающая обещание, которая иногда не срабатывает ...

function fnThatMightFail() {
    return new Promise((resolve, reject) => {
        let fail = Math.random() < 0.40;
        (fail)? reject('bad') : resolve('good');
    });
}

fnThatMightFail().then(result => {
    console.log(result);
}).catch(error => {
    console.log(error);
});

А потом, я думаю, вот рекурсивная идея, которую вы ищете.Передайте функцию и время ожидания между попытками, вызывайте рекурсивно, пока мы не добьемся успеха ...

function fnThatMightFail() {
    return new Promise((resolve, reject) => {
        let fail = Math.random() < 0.40;
        (fail)? reject('bad') : resolve('good');
    });
}

function timeoutPromise(ms) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(), ms);
    });
}

function fnRetryer(fn, tries, wait) {
    if (tries <= 0) return Promise.reject('bad');
    console.log('attempting fn');
    return fn().then(result => {
        console.log(`success: ${result}`);
        return result;
    }).catch(error => {
        console.log(`error: ${error}, retrying after ${wait}ms`);
        return timeoutPromise(wait).then(result => {
            console.log(`${wait}ms elapsed, recursing...`);
            return fnRetryer(fn, tries-1, wait);
        });
    });
}

fnRetryer(fnThatMightFail, 5, 1000).then(result => {
    console.log(`we tried (and maybe tried) and got ${result}`);
}).catch(error => {
    console.log('we failed after 5 tries, waiting 1s in between each try');
});

Обратите внимание, что вы можете добавить параметр для максимального количества попыток, уменьшить его при каждом рекурсивном вызове, а затем не выполнять рекурсию, если он достигнет нуля.Также обратите внимание, что при рекурсивном вызове вы можете увеличить время ожидания.

...