English 中文(简体)
明智的再造型设计模式
原标题:Promise Retry Design Patterns
  1. Pattern that keep on retrying until the promise resolves (with delay and maxRetries).
  2. Pattern that keeps on retrying until the condition meets on the result (with delay and maxRetries).
  3. A memory efficient dynamic Pattern with unlimited retries (delay provided).

www.un.org/Depts/DGACM/index_spanish.htm 第1号法典: 在承诺解决之前保持再产业(任何语言改进社区等)

Promise.retry = function(fn, times, delay) {
    return new Promise(function(resolve, reject){
        var error;
        var attempt = function() {
            if (times == 0) {
                reject(error);
            } else {
                fn().then(resolve)
                    .catch(function(e){
                        times--;
                        error = e;
                        setTimeout(function(){attempt()}, delay);
                    });
            }
        };
        attempt();
    });
};

用途

work.getStatus()
    .then(function(result){ //retry, some glitch in the system
        return Promise.retry(work.unpublish.bind(work, result), 10, 2000);
    })
    .then(function(){console.log( done )})
    .catch(console.error);

www.un.org/Depts/DGACM/index_spanish.htm 第2号()的编码在符合以下条件的前提下进行重新计算:then 导致可再使用的方式(条件会有所不同)。

work.publish()
    .then(function(result){
        return new Promise(function(resolve, reject){
            var intervalId = setInterval(function(){
                work.requestStatus(result).then(function(result2){
                    switch(result2.status) {
                        case "progress": break; //do nothing
                        case "success": clearInterval(intervalId); resolve(result2); break;
                        case "failure": clearInterval(intervalId); reject(result2); break;
                    }
                }).catch(function(error){clearInterval(intervalId); reject(error)});
            }, 1000);
        });
    })
    .then(function(){console.log( done )})
    .catch(console.error);
最佳回答

缩略语......

可以通过建立<条码>、副渔获物()链,而不是更常用的<条码>.then(链条来实现。

This approach is :

  • only possible with a specified maximum number of attempts. (The chain must be of finite length),
  • only advisable with a low maximum. (Promise chains consume memory roughly proportional to their length).

Otherwise, use a recursive solution.

First, a utility function to be used as a .catch() callback.

var t = 500;

function rejectDelay(reason) {
    return new Promise(function(resolve, reject) {
        setTimeout(reject.bind(null, reason), t); 
    });
}

现在,你可以非常简明地建立渔获链:

1. Retry until the promise resolves, with delay

var max = 5;
var p = Promise.reject();

for(var i=0; i<max; i++) {
    p = p.catch(attempt).catch(rejectDelay);
}
p = p.then(processResult).catch(errorHandler);

DEMO: https://jsfiddle.net/duL0qjqe/

2. Retry until result meets some condition, without delay

var max = 5;
var p = Promise.reject();

for(var i=0; i<max; i++) {
    p = p.catch(attempt).then(test);
}
p = p.then(processResult).catch(errorHandler);

rel=“noretinger”https://jsfiddle.net/duL0qjqe/1/

3. Retry until result meets some condition, with delay

Having got your mind round (1) and (2), a combined test+delay is equally trivial.

var max = 5;
var p = Promise.reject();

for(var i=0; i<max; i++) {
    p = p.catch(attempt).then(test).catch(rejectDelay);
    // Don t be tempted to simplify this to `p.catch(attempt).then(test, rejectDelay)`. Test failures would not be caught.
}
p = p.then(processResult).catch(errorHandler);

<>代码>测试()可以是同步或同步的。

添加进一步试验也是微不足道的。 简单地将两条捕获物之间的一个链条管束。

p = p.catch(attempt).then(test1).then(test2).then(test3).catch(rejectDelay);

rel=“noretinger”https://jsfiddle.net/duL0qjqe/3/


所有版本都设计为<条码>目标/代码>,作为承诺回报的功能。 它还可以设想将价值退回,在这种情况下,链条将沿着其成功的道路走到下一个/最终的<代码>。

问题回答

提到了许多很好的解决办法,现在,如果不作出很大努力,这些问题就可以得到解决。

如果你不考虑一种宽松的做法,那是我的解决方法。

function retry(fn, retries=3, err=null) {
  if (!retries) {
    return Promise.reject(err);
  }
  return fn().catch(err => {
      return retry(fn, (retries - 1), err);
    });
}

你可以把新的承诺带往前一个,从而拖延最终解决,直到你知道最终答案。 如果下一个答案还不为人所知,那么,在你最终知道答案并能够退回最后决议之前,再把另一个承诺链起来,并保持链条检查。 这样做可以做到:

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

function checkStatus() {
    return work.requestStatus().then(function(result) {
        switch(result.status) {
            case "success":
                return result;      // resolve
            case "failure":
                throw result;       // reject
            case default:
            case "inProgress": //check every second
                return delay(1000).then(checkStatus);
        }
    });
}

work.create()
    .then(work.publish) //remote work submission
    .then(checkStatus)
    .then(function(){console.log("work published"})
    .catch(console.error);

Note, I also avoided creating the promise around your switch statement. Since you re already in a .then() handler, just returning a value is resolve, throwing an exception is reject and returning a promise is chaining a new promise onto the prior one. That covers the three branches of your switch statement without creating a new promise in there. For convenience, I do use a delay() function that is promise based.

FYI假定“work.requestStatus()不需要任何论据。 如果确实需要某些具体论点,你就可以在职能要求时通过这些论点。


It might also be a good idea to implement some sort of timeout value for how long you will loop waiting for completion so this never goes on forever. You could add the timeout functionality like this:

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

function checkStatus(timeout) {
    var start = Date.now();

    function check() {
        var now = Date.now();
        if (now - start > timeout) {
            return Promise.reject(new Error("checkStatus() timeout"));
        }
        return work.requestStatus().then(function(result) {
            switch(result.status) {
                case "success":
                    return result;      // resolve
                case "failure":
                    throw result;       // reject
                case default:
                case "inProgress": //check every second
                    return delay(1000).then(check);
            }
        });
    }
    return check;
}

work.create()
    .then(work.publish) //remote work submission
    .then(checkStatus(120 * 1000))
    .then(function(){console.log("work published"})
    .catch(console.error);

我并不确切地确定你们重新寻找什么“设计模式”。 由于你似乎反对外部宣布的<代码>checkStatus()功能,因此,这里的行文版是:

work.create()
    .then(work.publish) //remote work submission
    .then(work.requestStatus)
    .then(function() {
        // retry until done
        var timeout = 10 * 1000;
        var start = Date.now();

        function check() {
            var now = Date.now();
            if (now - start > timeout) {
                return Promise.reject(new Error("checkStatus() timeout"));
            }
            return work.requestStatus().then(function(result) {
                switch(result.status) {
                    case "success":
                        return result;      // resolve
                    case "failure":
                        throw result;       // reject
                    case default:
                    case "inProgress": //check every second
                        return delay(1000).then(check);
                }
            });
        }
        return check();
    }).then(function(){console.log("work published"})
    .catch(console.error);

A more reusable retry scheme that could be used in many circumstances would define some reusable external code, but you seem to object to that so I haven t made that version.


此处采用<代码>.retry Until()方法,按您的请求使用Promise.prototype。 如果你想要弄清这方面的执行细节,你就应当能够修改这一总体做法:

// fn returns a promise that must be fulfilled with an object
//    with a .status property that is "success" if done.  Any
//    other value for that status means to continue retrying
//  Rejecting the returned promise means to abort processing 
//        and propagate the rejection
// delay is the number of ms to delay before trying again
//     no delay before the first call to the callback
// tries is the max number of times to call the callback before rejecting
Promise.prototype.retryUntil = function(fn, delay, tries) {
    var numTries = 0;
    function check() {
        if (numTries >= tries) {
            throw new Error("retryUntil exceeded max tries");
        }
        ++numTries;
        return fn().then(function(result) {
            if (result.status === "success") {
                return result;          // resolve
            } else {
                return Promise.delay(delay).then(check);
            }
        });
    }
    return this.then(check);
}

if (!Promise.delay) {
    Promise.delay = function(t) {
        return new Promise(function(resolve) {
            setTimeout(resolve, t);
        });
    }
}


work.create()
    .then(work.publish) //remote work submission
    .retryUntil(function() {
        return work.requestStatus().then(function(result) {
            // make this promise reject for failure
            if (result.status === "failure") {
                throw result;
            }
            return result;
        })
    }, 2000, 10).then(function() {
        console.log("work published");
    }).catch(console.error);

I still can t really tell what you want or what about all these approaches is not solving your issue. Since your approaches seem to all be all inline code and not using a resuable helper, here s one of those:

work.create()
    .then(work.publish) //remote work submission
    .then(function() {
        var tries = 0, maxTries = 20;
        function next() {
            if (tries > maxTries) {
                throw new Error("Too many retries in work.requestStatus");
            }
            ++tries;
            return work.requestStatus().then(function(result) {
                switch(result.status) {
                    case "success":
                        return result;
                    case "failure":
                        // if it failed, make this promise reject
                        throw result;
                    default:
                        // for anything else, try again after short delay
                        // chain to the previous promise
                        return Promise.delay(2000).then(next);
                }

            });
        }
        return next();
    }).then(function(){
        console.log("work published")
    }).catch(console.error);

Here is an "exponential backoff" retry implementation using async/await that can wrap any promise API.

note:, 出于示范原因,用Math.random简单明了的圆顶端点,这样就能够看到成功和失败的案例。

/**
 * Wrap a promise API with a function that will attempt the promise 
 * over and over again with exponential backoff until it resolves or
 * reaches the maximum number of retries.
 *   - First retry: 500 ms + <random> ms
 *   - Second retry: 1000 ms + <random> ms
 *   - Third retry: 2000 ms + <random> ms
 * and so forth until maximum retries are met, or the promise resolves.
 */
const withRetries = ({ attempt, maxRetries }) => async (...args) => {
  const slotTime = 500;
  let retryCount = 0;
  do {
    try {
      console.log( Attempting... , Date.now());
      return await attempt(...args);
    } catch (error) {
      const isLastAttempt = retryCount === maxRetries;
      if (isLastAttempt) {
        // Stack Overflow console doesn t show unhandled
        // promise rejections so lets log the error.
        console.error(error);
        return Promise.reject(error);
      }
    }
    const randomTime = Math.floor(Math.random() * slotTime);
    const delay = 2 ** retryCount * slotTime + randomTime;
    // Wait for the exponentially increasing delay period before 
    // retrying again.
    await new Promise(resolve => setTimeout(resolve, delay));
  } while (retryCount++ < maxRetries);
}

const fakeAPI = (arg1, arg2) => Math.random() < 0.25 
  ? Promise.resolve(arg1) 
  : Promise.reject(new Error(arg2))
  
const fakeAPIWithRetries = withRetries({ 
  attempt: fakeAPI, 
  maxRetries: 3 
});

fakeAPIWithRetries( arg1 ,  arg2 )
 .then(results => console.log(results))

我在此试图。 我试图从上述所有答复中接受我一样的内容。 没有外部依赖。 打字/等待(ES2017)

export async function retryOperation<T>(
  operation: () => (Promise<T> | T), delay: number, times: number): Promise<T> {
    try {
      return await operation();
    } catch (ex) {
      if (times > 1) {
        await new Promise((resolve) => setTimeout(resolve, delay));
        return retryOperation(operation, delay, times - 1);
      } else {
        throw ex;
      }
    }
}

使用:

function doSomething() {
  return Promise.resolve( I did something! );
}

const retryDelay = 1000; // 1 second
const retryAttempts = 10;


retryOperation(doSomething, retryDelay, retryAttempts)
    .then((something) => console.log( I DID SOMETHING ))
    .catch((err) => console.error(err));

以微薄的清洁法和拖延办法为基础

// Retry code

const wait = ms => new Promise((resolve) => {
  setTimeout(() => resolve(), ms)
})


const retryWithDelay = async (
  fn, retries = 3, interval = 50,
  finalErr = Error( Retry failed )
) => {
  try {
    await fn()
  } catch (err) {
    if (retries <= 0) {
      return Promise.reject(finalErr);
    }
    await wait(interval)
    return retryWithDelay(fn, (retries - 1), interval, finalErr);
  }
}

// Test

const getTestFunc = () => {
  let callCounter = 0
  return async () => {
    callCounter += 1
    if (callCounter < 5) {
      throw new Error( Not yet )
    }
  }
}

const test = async () => {
  await retryWithDelay(getTestFunc(), 10)
  console.log( success )
  await retryWithDelay(getTestFunc(), 3)
  console.log( will fail before getting here )  
}


test().catch(console.error)

这里有大量答案,但经过一些研究,我决定采取宽松的办法。 让我在此向任何感兴趣的人提出解决办法

function retry(fn, retriesLeft = 2, interval = 1000) {
  return new Promise((resolve, reject) => {
    fn()
      .then(resolve)
      .catch((error) => {
        if (retriesLeft === 0) {
          reject(error);
          return;
        }

        setTimeout(() => {
          console.log( retrying... )
          retry(fn, retriesLeft - 1, interval).then(resolve).catch(reject);
        }, interval);
      });
  });
}

这里是一根ice子,可以让大家感觉到它是如何运作的。 围绕意图变量进行公正的游戏,以看到承诺的决心/反对

https://js-vjramh.stackblitz.io

不能确定为什么所有提议的解决办法都是休庭的。 一种重复性的解决办法,即,在这种方法归还未经界定的物品之前,应等待:

function DelayPromise(delayTime): Promise<void> {
  return new Promise<void>((resolve) => setTimeout(resolve, delayTime));
}

interface RetryOptions {
  attempts?: number;
  delayMs?: number;
}

export async function retryOperation<T>(
  operation: (attempt: number) => Promise<T>,
  options: RetryOptions = {}
): Promise<T> {
  const { attempts = 6, delayMs = 10000 } = options;
  for (let i = 0; i < attempts; i++) {
    const result = await operation(i);
    if (typeof result !==  undefined ) {
      return result;
    }
    await DelayPromise(delayMs);
  }
  throw new Error( Timeout );
}

Here is my solution:

  • Preserve function type using Typescript.
  • Accept a function with any parameters.
  • Customize number of maxRetries.
  • Customize delay behavior
type AnyFn = (...any: any[]) => any;
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
type DelayFn = (retry: number) => number;

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

export function retry<Fn extends AnyFn>(
  fn: Fn,
  maxRetries: number,
  getDelay: DelayFn = () => 5000
) {
  let retries = 0;

  return async function wrapped(
    ...args: Parameters<Fn>
  ): Promise<Awaited<ReturnType<Fn>>> {
    try {
      return await fn(...args);
    } catch (e) {
      if (++retries > maxRetries) throw e;

      const delayTime = getDelay(retries);
      console.error(e);
      console.log(`Retry ${fn.name} ${retries} times after delaying ${delayTime}ms`);
      await delay(delayTime);
      return await wrapped(...args);
    }
  };
}

Usage

const badFn = () => new Promise((resolve, reject) => reject( Something is wrong );
const fn = retry(badFn, 5, (retry) => 2 ** retry * 1000);

fn();

// Something is wrong
// Retry badFn 1 times after delaying 2000ms
// Something is wrong
// Retry badFn 2 times after delaying 4000ms
// Something is wrong
// Retry badFn 3 times after delaying 8000ms
// Something is wrong
// Retry badFn 4 times after delaying 16000ms
// Something is wrong
// Retry badFn 5 times after delaying 32000ms

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

function retry(fn, maxRetries, getDelay = () => 5000) {
  let retries = 0;

  return async function wrapped(...args) {
    try {
      return await fn(...args);
    } catch (e) {
      if (++retries > maxRetries) throw e;
      const delayTime = getDelay(retries);
      console.error(e);
      console.log(`Retry ${fn.name} ${retries} times after delaying ${delayTime}ms`);
      await delay(delayTime);
      return await wrapped(...args);
    }
  };
}

const badFn = () => new Promise((resolve, reject) => reject( Something is wrong ));
const fn = retry(badFn, 5, (retry) => 2 ** retry * 1000);

fn();
function TryToSuccess(fun, reties) {
    let attempt = 0;

    let doTry = (...args) => {
        attempt++;
        return fun(...args)
                .catch((err) => {
                    console.log("fail ", attempt);
                    if(attempt <= reties){
                        return doTry(...args);
                    } else {
                        return Promise.reject(err);
                    }
                });
    }

    return doTry;
}

function asyncFunction(){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            (window.findResult === true) ? resolve("Done") : reject("fail");
        }, 2000);
    });
}

var cloneFunc = TryToSuccess(asyncFunction, 3);

cloneFunc()
    .then(res => { 
        console.log("Got Success. ", res)
    })
    .catch(err => { 
        console.log("Rejected with err ", err); 
    });

setTimeout(() => {
    window.findResult = true;
}, 4000);

async-retry.ts 正在尝试实施这一模式,在某些项目的生产中使用这一模式。

Installation:

npm install async-retry.ts --save

Usage:

import Action from  async-retry.ts 
 
const action = async()=>{}
const handlers = [{
  error:  error1 ,
  handler: async yourHandler1()=>{}
}, {
  error:  error2 ,
  handler: async yourHandler2()=>{}
}]
 
await Action.retryAsync(action, 3, handlers)

这一一揽子计划是相当新的,但源于长期一揽子计划:co-retry>,后者在发电机功能时采用了<>retry patterns。

work.create()
    .then(work.publish) //remote work submission
    .then(function(result){
        var maxAttempts = 10;
        var handleResult = function(result){
            if(result.status ===  success ){
                return result;
            }
            else if(maxAttempts <= 0 || result.status ===  failure ) {
                return Promise.reject(result);
            }
            else {
                maxAttempts -= 1;
                return (new Promise( function(resolve) {
                    setTimeout( function() {
                        resolve(_result);
                    }, 1000);
                })).then(function(){
                    return work.requestStatus().then(handleResult);
                });
            }
        };
        return work.requestStatus().then(handleResult);
    })
    .then(function(){console.log("work published"})
    .catch(console.error);

我的解决办法是:

export const wait = (milliseconds: number): Promise<void> =>
  new Promise(resolve => {
    setTimeout(() => resolve(), milliseconds);
  });

export const retryWithDelay = async (
  fn,
  retries = 3,
  interval = 300
): Promise<void> =>
  fn().catch(async error => {
    if (retries <= 0) {
      return Promise.reject(error);
    }
    await wait(interval);
    return retryWithDelay(fn, retries - 1, interval);
  });

根据上述解决办法,固定的流体会等待,因为它将拖欠50秒钟,而不是ms,现在留下了造成失败的错误,而不是硬编码的散射。

我给你一个yn子/红it的解决办法:

async function scope() {

  /* Performs an operation repeatedly at a given frequency until
     it succeeds or a timeout is reached and returns its results. */
  async function tryUntil(op, freq, tout) {
    let timeLeft = tout;
    while (timeLeft > 0) {
      try {
        return op();
      } catch (e) {
        console.log(timeLeft + " milliseconds left");
        timeLeft -= freq;
      }
      await new Promise((resolve) => setTimeout(() => resolve(), freq));
    }
    throw new Error("failed to perform operation");
  }

  function triesToGiveBig() {
    const num = Math.random();
    if (num > 0.95) return num;
    throw new Error();
  }

  try {
    console.log(await tryUntil(triesToGiveBig, 100, 1000));
  } catch (e) {
    console.log("too small :(");
  }

}

scope();

就像有些人正在寻求一种更通用的解决办法。 这里是我的两点:

Helper Function:

/**
 * Allows to repeatedly call
 * an async code block
 *
 * @callback callback
 * @callback [filterError] Allows to differentiate beween different type of errors
 * @param {number} [maxRetries=Infinity]
 */
function asyncRetry(
  callback,
  { filterError = (error) => true, maxRetries = Infinity } = {}
) {
  // Initialize a new counter:
  let tryCount = 0;
  // Next return an async IIFY that is able to
  // call itself recursively:
  return (async function retry() {
    // Increment out tryCount by one:
    tryCount++;
    try {
      // Try to execute our callback:
      return await callback();
    } catch (error) {
      // If our callback throws any error lets check it:
      if (filterError(error) && tryCount <= maxRetries) {
        // Recursively call this IIFY to repeat
        return retry();
      }
      // Otherwise rethrow the error:
      throw error;
    }
  })();
}

Demo

<><>Try 2倍:

await asyncRetry(async () => {
  // Put your async code here
}, { maxRetries = 2 })

www.un.org/Depts/DGACM/index_spanish.htm Try 2er & only retry on DOMErrors:

await asyncRetry(async () => {
  // Put your async code here
}, { 
  maxRetries = 2,
  filterError: (error) => error instance of DOMError
})

www.un.org/Depts/DGACM/index_spanish.htm Infine Retry:

await asyncRetry(async () => {
  // Put your async code here
})

简单易懂的产业:

function keepTrying(otherArgs, promise) {
    promise = promise||new Promise();
    
    // try doing the important thing
    
    if(success) {
        promise.resolve(result);
    } else {
        setTimeout(function() {
            keepTrying(otherArgs, promise);
        }, retryInterval);
    }
}

这对我来说是完美的:

async wait(timeInMilliseconds: number, name?: string) {
    const messageSuffix = name ? ` => ${name}` : ""
    await this.logger.info(`Waiting for ${timeInMilliseconds} ms${messageSuffix}`).then(log => log())
    return new Promise<void>(resolve => setTimeout(resolve, timeInMilliseconds))
}

async waitUntilCondition(name: string, condition: () => boolean | Promise<boolean>, scanTimeInSeconds: number, timeoutInSeconds: number) {
    await this.logger.info(`Waiting until condition: name=${name}, scanTime: ${scanTimeInSeconds} s, timeout: ${timeoutInSeconds} s`).then(log => log())
    const timeoutInMillis = timeoutInSeconds * 1000
    return new Promise<void>(async (resolve, reject) => {
        const startTime = new Date().getTime()
        let completed = false
        let iteration = 0
        while (!completed) {
            if (iteration++ > 0) {
                const timingOutInSeconds = Math.round((timeoutInMillis - (new Date().getTime() - startTime)) / 1000.0)
                await this.wait(scanTimeInSeconds * 1000, `${name}, timing out in ${timingOutInSeconds} s`)
            }
            try {
                completed = await condition()
                if (completed) {
                    resolve()
                    return
                }
            } catch (error: any) {
                reject(error)
                throw error
            }
            const waitTimeMillis = new Date().getTime() - startTime
            if (waitTimeMillis > timeoutInMillis) {
                reject(`The condition  ${name}  timed out. Time waited: ${waitTimeMillis / 1000} seconds`)
                return
            }
        }
    })
}

An approach with control on if the operation can indeed be retried

In practice, I found that we shouldn t assume that the operation is always retryable, and the generic retry helper needs a way to delegate that check to the higher level calling code. The example below shows what worked for me.


/* The retry function takes a function to invoke, and a set 
 * of optional parameters to control the delay between retries 
 * (no backoff algorithm implemented here, but other example 
 * show how you might add that one), how many times to attempt
 * retrying and also a way to check if a retry should be 
 * attempted.
 *
 * And it returns a Promise that can be used in promise-
 * chaining and other async patterns.
 *
 */
const retry = (fn, 
               ms = 1000, 
               maxRetries = 2, 
               fnRetryable) => new Promise((resolve, reject) => {

  var retries = 0;

  if(!fnRetryable) {
    // default to always retryable
    fnRetryable = function() { return true };
  }

  fn()
  .then(resolve)
  .catch((err) => {
    if(!fnRetryable(err)) {
      return reject( Non-retryable );
    } else {
      setTimeout(() => {
        ++retries;
        if(retries == maxRetries) {
          return reject( Max retries exceeded );
        }
        retry(fn, ms).then(resolve);
      }, ms);
    }
  })
});

function doFoo(opts) {
  // Return a Promise that resolves after doing something with opts
  // or rejects with err.statusCode
}

function doFooWithRetry(opts, ms = 1000, maxRetries = 2) {
  var attempt = function() {
    return doFoo(opts);
  }
  var retryable = function(err) {
    // example, retry on rate limit error
    if(err && err.statusCode == 429) {
      return true;
    } else {
      return false;
    }
  }

  return retry(attempt, ms, maxRetries, retryable);
}

唯一易于使用和纯javascript 0 Depend async-retry Library 你们永远需要。

const { retry } = require( @ajimae/retry )

function exec() {
  // This will be any async or sync action that needs to be retried.
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({ message:  some async data  })
    }, 1500)
  })
}

// takes the response from the exec function and check if the condition/conditions are met
function predicate(response, retryCount) {
  console.log(retryCount) // goes from 0 to maxRetries 

  // once this condition is met the retry exits
    return (response.message ==  some async data )
}

(async function main() {
  // enable or disable an exponential backoff behaviour if needed.
  const result = await retry(exec, predicate, { maxRetries: 5, backoff: true })
  console.log(result) // { message:  some async data  } 
})()

PS:我撰写了library

作为loop-based .then( approach,将一系列任意的承诺合并起来。 第一项承诺一旦获得解决,便可绕过一个“蓝色编码”,以阻止任何进一步的承诺。

const repeatUntilOK = (fn, tries = 10) => {
  let done = false;
  let p = Promise.resolve();
  let result;

  for (let i = 0; i < tries; i++) {
    p = p
      .then(() =>
        result = (done ? result : fn())
      )
      .then(result => {
        done = true;
        return result;
      })
      .catch(() => {
        if (i >= tries - 1) {
          throw Error(
            `Function never resolved after ${tries} tries`
          );
        }
      });
  }

  return p;
};

// contrived test example
let i = 0;
repeatUntilOK(() => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (i++ < 5) {
        console.log("failed, retrying...");
        return reject();
      }

      console.log("done");
      resolve(42);
    }, 1000);
  });
}, 8)
  .then(result => console.log("result:", result))
  .catch(err => console.error(err));

如果你想要的话,你可以放弃睡觉(很可能采用像指数背书这样的办法),但这种功能是通用的,因此,如上所示,打电话者可以确定在试射中是否睡觉。

使用<代码>sync/>await<>/code>肯定更好,但并非所有环境都支持这一系统,我目前的项目就是这样。





相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.