Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 159 题:实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject #387

Open
yygmind opened this issue May 21, 2020 · 71 comments
Labels

Comments

@yygmind
Copy link
Contributor

yygmind commented May 21, 2020

No description provided.

@yygmind yygmind changed the title 第 159 题:实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject 第 159 题:实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject May 21, 2020
@yygmind yygmind added the 异步 label May 21, 2020
@bighamD
Copy link

bighamD commented May 21, 2020

Promise.retry = function (promiseFn, times = 3) {
  return new Promise(async (resolve, reject) => {
    while (times--) {
      try {
        var ret = await promiseFn();
        resolve(ret);
        break;
      } catch (error) {
        if (!times) reject(error);
      }
    }
  });
};
function getProm() {
    const n = Math.random();
    return new Promise((resolve, reject) => {
        setTimeout(() =>  n > 0.9 ? resolve(n) : reject(n), 1000);
    });
}
Promise.retry(getProm);

@liujiekun
Copy link

image

@FunnyBoyCN
Copy link

image

@ShinningFire
Copy link

image

@weiweixuan
Copy link

写的不好,有好的写法大家可以指点一下,感谢

/*
          实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject
        */

      // 同步获得Promise状态和值,这样写很low,要是更好的写法大家call我一下
      async function checkPromise(getFlag) {
        try {
          let res = await getFlag();
          return { flag: true, value: res };
        } catch (e) {
          return { flag: false, value: e };
        }
      }

      async function retry(pro, count = 10) {
        let result = {
            flag: false,
            value: null,
          },
          length = count;
        while (count && !result.flag) {
          console.log(`调用了${length - count + 1}次`);
          result = await checkPromise(pro);
          const { flag, value } = result;
          if (!flag) {
            count--;
          }
        }
        return result.value;
      }
      Promise.retry = retry;

      getFlag = function () {
        return Math.random() > 0.5 ? Promise.resolve(1) : Promise.reject(-1);
      };

      Promise.retry(getFlag, 10)
        .then((res) => {
          console.log("成功结果", res);
        })
        .catch((e) => {
          console.log("失败结果", e);
        });

@fanefanes
Copy link

fanefanes commented May 21, 2020

 Promise.retry = function(fn, num){
    return new Promise(function(resolve, reject){
       while(num>0){
           try{
                  const res = await fn
                  resolve(res)
                  num = 0
            } catch(e){
                  if(!num) reject(e)
            }
            num --
        }
    })
}

@listentolife
Copy link

function retry (fn, count = 10) {
  return new Promise(async (resolve, reject) => {
    while (count) {
      try {
        let res = await fn()
        resolve(res)
        return
      } catch (e) {
        if (!count) reject(e)
        count--
      }
    }
  })
}

@rottenpen
Copy link

rottenpen commented May 25, 2020

/** 
 * 实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject 
*/
Promise.retry = function(fn, limit) {
  let i = 0
  return new Promise((resolve, reject) => {
    function retry() {
      console.log('try!', i)
      fn().then(res => {
        resolve()
      }).catch(err => {
        i++
        if(i > limit - 1) {
          reject(err)
        } else {
          retry()
        }
      })
    }
    retry()
  })
  
}
Promise.retry(() => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > .5 ? resolve() : reject()
    }, 300);
  })
}, 5).then(res => {
  console.log('resolve')
}).catch(err => {
  console.log('reject')
})

@huangzhiyang166
Copy link

image

@ghost
Copy link

ghost commented May 27, 2020

方法一:在 catch() 中再次执行函数

Promise.retry = function (fn, times) {
  fn().then(console.log)
    .catch(e => {
      if (times > 0) {
        console.log('try again...')
        Promise.retry(fn, times - 1)
      } else {
        console.log('Error: No more times, now rejected.')
      }
    })
}

方法二:async 函数,结合 while 循环和 try...catch

Promise.retry = async function (fn, times) {
  while (times > 0) {
    try {
      const res = await fn()
      console.log(res)
      return
    } catch(e) {
      console.log('try again...')
      times--
    }
  }
  console.log('Error: No more times, now rejected.')
}

测试:

const test = function () {
  return new Promise((resolve, reject) => {
    const num = Math.floor(Math.random() * 10)
    if (num > 7) {
      resolve(num)
    } else {
      reject(new Error(num))
    }
  })
}

Promise.retry(test, 5)

@hugeorange
Copy link

记得几年前面试一次面试时问过类似的问题,当时绞尽脑汁也没想出解决办法



/**
 * promiseFn 返回promise 对象的函数
 * max       最大重试次数
 * interval  重试间隔时间
*/
Promise.retry = function (promiseFn, max=1, interval = 1000) {
    function excuteFn(max) {
        return promiseFn().then(res => {
            return Promise.resolve(res);
        }, err => {
            if (max <= 1) {
                return Promise.reject(err);
            } else {
                return new Promise((resolve, reject) => {
                    setTimeout(() => {
                        resolve(excuteFn(--max));
                    }, interval);
                })
            }
        })
    }
    return excuteFn(max)
}


// 测试用例
Promise.retry(ajax, 5, 1000)
    .then(res => console.log('retry-res->', res))
    .catch(err => console.log('retry-err->', err))



function ajax() {
    const n = Math.random();
    console.log('--->', n)
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (n > 0.9) {
                resolve(`成功返回值--->${n}`)
            } else {
                reject(`失败返回值--->${n}`)
            }
        }, 3000);
    })
}

@dice246
Copy link

dice246 commented May 29, 2020

// 实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject 
Promise.retry = function(fn, num){
  return new Promise(async function(resolve, reject){
     while(num>0){
         try{
            const res = await fn();
            console.log('res: ', res);
            resolve(res)
            num = 0
          } catch(e){
            console.log('reject....');
            if(num === 1) reject(e);
            num--
          }
      }
  })
}

const test = () => {
  return new Promise((resolve, reject) => {
    const num = Math.floor(Math.random() * 10);
    if (num > 5) {
      resolve(num);
    } else {
      reject(`num 小于等于8`);
    }
  
  })
}

Promise
.retry(test, 5)
.then(res => {
  console.log('result: ', res);
})
.catch(err => {
  console.log('err: ', err);
})

@lvanboy
Copy link

lvanboy commented Jun 1, 2020

更加具有抽象形式的retry,尝试反复执行一个方法,方法内部可以是异步请求,或者其他需要retry的动作,如请求动画等等。所以,我给出的retry函数的ts形式是这样的。

function retry(times:number,fn:Function){
    let counter = 0,maxTimes = times +1;
    let resp , err;
    while(counter < maxTimes){
           err = undefined;
           try{
                resp = fn();
           }catch(error){
                err = error;
           }
           if(err === undefined){
                 break;
           }
    }
    if(err){
       throw err;
    }

    return resp;
}

retry(3,()=>{
  console.log("test");
  throw new Error("retry error")
  return {}
})

@MengYiFan
Copy link

// 实现 Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 reject
// 这道题刚开始做的时候,写漏了一个条件:超过一定次数才是真正的reject。
// 这里用for + break 去做次数限制
Promise.retry = function(fn, max = 5) {
    return new Promise(async (resolve, reject) => {
        let res = null
        for (let i in [...Array(max)]) {
            try {
               console.log('try: ', i)
               res = await fn()
               break
            } catch(e) {
                if(+i === (max - 1)) {
                    reject(e)
                    return
                }
            }
        }
        resolve(res)
    })
}

function fn () {
    let n = Math.random()
    return new Promise((resolve, reject) => {
        setTimeout(() => {
           console.log('Current random value: ', n)
           n > 0.75 ? resolve(n) : reject(n)
        }, 2000)
    })
}

Promise.retry(fn, 10)
.then(res => console.log('Resolve: ', res))
.catch(res => console.log('Reject: ', res))

@qianlongo
Copy link

感觉题目可以清晰一些,指定retry的入参是啥

 Promise.retry = function (fn, times) {
   return new Promise((rs, rj) => {
      return fn().then((res) => {
        rs(res)
      }).catch((err) => {
        if (--times >= 0) {
          return Promise.retry(fn, times)
        } else {
          rj(err)
        }
      })
   })
 }

@ZangYuSong
Copy link

ZangYuSong commented Jun 8, 2020

为啥感觉你们写的怎么这么复杂 。。。

Promise.retry = function (promiseFunc, num = 2) {
  return promiseFunc().then(null, (e) => {
    if (num > 0) {
      num -= 1;
      console.log("重试");
      return Promise.retry(promiseFunc, num);
    }
    return Promise.reject(e);
  });
};

再简化一下

Promise.retry = function (promiseFunc, num = 2) {
  return promiseFunc().then(null, (e) => num > 0 ? Promise.retry(promiseFunc, num - 1) : Promise.reject(e));
};

@sfsoul
Copy link

sfsoul commented Jun 11, 2020

感觉题目可以清晰一些,指定retry的入参是啥

 Promise.retry = function (fn, times) {
   return new Promise((rs, rj) => {
      return fn().then((res) => {
        rs(res)
      }).catch((err) => {
        if (--times >= 0) {
          return Promise.retry(fn, times)
        } else {
          rj(err)
        }
      })
   })
 }

我就想问这一句:return fn().then((res) => rs(res));
题目没说fn函数返回的一定是Promise吧?普通函数调用then不就报错了

@GuoYiJi
Copy link

GuoYiJi commented Jun 12, 2020

(function () {

  function retry(func, max = 2, err) {
    return new Promise((resolve, reject) => {
      return func()
        .then(resolve)
        .catch(err => {
          console.log('retry', max);
          if (max <= 0) {
            return reject(err)
          }
          return retry(func, max - 1);
        })
        .catch(reject);
      
    })
  }


  retry(() => Promise.resolve(1))
    .then(res => {
      console.log('成功', 1)
    })
    .catch(err => {
      console.log('fail');
    })

  retry(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(111);
      }, 3000);
    })
  })
    .then(res => {
      console.log('成功', res)
    })
    .catch(err => {
      console.log('fail', err);
    })



})();

@jefferyE
Copy link

jefferyE commented Jun 15, 2020

if (Promise) {
  Promise.retry = function (fn, time) {
    return new Promise((resolve, reject) => {
      const retry = (i) => {
        return Promise.resolve(fn()).then(res => {
          resolve(res);
        }).catch(err => {
          if (i <= time) {
            return retry(++i);
          } else {
            reject(err);
          }
        })
      }
      return retry(0);
    });
  }
}

Promise.retry(function () {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve('resolve...');
    reject('reject...');
  }, 300);
 });
}, 3).then(res => {
  console.log('res: ', res);
}).catch(err => {
  console.log('err:', err);
});

@NathanHan1
Copy link

Promise.retry = function (task, retryTimes) {
        if(retryTimes <= 0) {
          new Error('wrong params that retry times')
        }
        return new Promise((resolve, reject) => {
          function runTask() {
            if(retryTimes === 0) {
              reject(new Error('have no retry times'))
              return
            }
            task()
              .then((v) => {
                resolve(`success ${v}`);
              })
              .catch(() => {
                retryTimes--
                runTask()
              });
          }
          runTask();
        });
      };

@leirensheng
Copy link

leirensheng commented Jun 26, 2020

Promise.retry = function (getPromise, num) {
  if (num === 1) return getPromise()
  return getPromise().then(res => res, () => Promise.retry(getPromise, --num))
}

@xuj2017
Copy link

xuj2017 commented Jun 30, 2020

Promise.retry = function(fn,max = 3){
	let count = 0;
	return new Promise((resolve,reject)=>{
		 function handler(){
			fn().then((res)=>{
				resolve(res)
			}).catch((err)=>{
				count++;
				if(count >= max){
					reject(err)
				}else{
					handler()
				}
			})
		}

		handler()
	})
}

@yuanyu4
Copy link

yuanyu4 commented Jul 3, 2020

Promise.retry = (times = 10, fn) =>
  // eslint-disable-next-line no-async-promise-executor
  new Promise(async (resolve, reject) => {
    while (times > 0) {
      // eslint-disable-next-line no-param-reassign
      times -= 1;
      try {
        // eslint-disable-next-line no-await-in-loop
        const ret = await fn();
        return resolve(ret);
      } catch (err) {
        if (times <= 0) {
          return reject(err);
        }
      }
    }
  });

// Test case
const test = () => new Promise((resolve, reject) => {
  if (Math.random() < 0.2) {
    resolve('good luck');
  } else {
    reject(new Error('bad luck'));
  }
});


Promise.retry(2, test).then((ret) => {
  console.log(ret);
}).catch((err) => {
  console.log(err);
});

@ustchcl
Copy link

ustchcl commented Jul 5, 2020

async function retry<T>(n: number, action: () => Promise<T>): Promise<T> {
  if (n <= 0) throw "Try all"
  try {
    let result = await action()
    return result
  } catch(_) {
    return retry(n - 1, action)
  }
}

@zhangwinning
Copy link

比如重试 5 次

let time = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("error");
    }, 1000);
  });
};

async function f(retry = 5) {
  while (retry !== 0) {
    try {
      const result = await time();
      return result;
    } catch (e) {
      if (--retry === 0) {
        throw e
      }
    }
  }
}

@darkestinblack
Copy link

//函数
Promise.retry = function (promise, num) {
    console.log(num);
    return promise().then(res => res, function () {
        return num == 1 ? promise() : Promise.retry(promise, --num)
    });
}
//箭头函数
Promise.retry = (promise, num) =>
    promise().then(res => res, () =>
        num == 1 ? promise() : Promise.retry(promise, --num)
    );


//test
Promise.retry(Promise.resolve.bind(Promise, "reslove"), 5);
Promise.retry(Promise.reject.bind(Promise, "reject"), 5);

@wenchao0809
Copy link

实现

对于常见的应用场景,至少应该满足重试次数和每次重试的间隔可配置,失败后立即重试意义并不大。

/**
 * Promise.retry,成功后 resolve 结果,失败后重试,尝试超过一定次数才真正的 rejec
 * @param {(resolve, reject) => any} fn 执行函数
 * @param {number} max 最大尝试次数
 * @param {number} interval 尝试间隔 
 * @param {number} count 函数内部统计 
 */
export function retry(fn, max = 1, interval = 1000, count = 0) {
  --max
  ++count
  return new Promise((resolve, reject) => {
    const wrapResolve = (res) => {
      resolve(res)
    }
    const wrapReject = (error) => {
      if (max >= 0) {
        setTimeout(() => {
          console.log(`第${count}次重试`)
          resolve(retry(fn, max, interval, count))
        }, interval)
      } else {
        reject(error)
      }
    }
    fn(wrapResolve, wrapReject)
  })
}

Promise.retry = retry

测试

// 单纯的失败场景
function testFail(_, reject) {
  reject(new Error('error'))
}
Promise.retry(testFail, 10)
  .catch(error => conso.log(error)
// 单纯的成功场景
function testSuccess(resolve) {
  resolve('success')
}
Promise.retry(testSuccess, 10)
  .then(res => console.log(res))
// 重试成功的场景
let count = 0
function testRetrySuccess(resolve, reject) {
  ++count
  count > 3 ? resolve('success') : reject(new Error('error'))
}
Promise.retry(testRetrySuccess, 10)
  .then(res => console.log(res))

@ReAlign
Copy link

ReAlign commented Nov 24, 2020

实现

Promise.retry = (fn = () => {}, times = 0) =>
  new Promise(async (resolve, reject) => {
    let count = -1;
    retryTask: 
    while (count < times) {
      try {
        (count !== -1) && console.log(`retry No.${count + 1}`);
        const res = await fn();
        resolve(res);
        break retryTask;
      } catch (err) {
        (++count === times) && reject(err);
      }
    }
  });

测试

// test function
const task = () => {
  return new Promise((resolve, reject) => {
    console.log('task run');
    setTimeout(() => {
        reject(new Error());
    }, 1000);
  })
};
// case1
Promise.retry(task).then(res => {
  console.log('Task1 resolved');
}).catch(err => {
  console.error('Task1 rejected, error is:', err);
})

image

// case2
Promise.retry(task, 1).then(res => {
  console.log('Task2 resolved');
}).catch(err => {
  console.error('Task2 rejected, error is:', err);
})

image

// case3
Promise.retry(task, 6).then(res => {
  console.log('Task3 resolved');
}).catch(err => {
  console.error('Task3 rejected, error is:', err);
})

image

@xiaowuge007
Copy link

var count = 1;

	function ajax() {
		return new Promise((resolve, reject) => {
			setTimeout(() => {
				if (count > 4) {
					resolve('success')
				} else {
					count++;
					reject('error')
				}
			}, 1000)
		})
	}

	Promise.retry = function (promise, num) {
		let c = 1;
		return new Promise((resolve, reject) => {
			function loop() {
				promise().then(res => {
					resolve(res)
				}).catch(err => {
					if (c > num) {
						reject(err)
					} else {
						c++
						loop();
					}
				})
			}

			loop()
		})

	}
	Promise.retry(ajax, 8).then(res => {
		console.log(res)
	}).catch(err => {
		console.log(err)
	})

@Luz-Liu
Copy link

Luz-Liu commented Feb 20, 2021

function retry2(fn, times) {
	times--;
	return new Promise((resolve, reject) => {
		resolve(fn());
	})
		.then((res) => {
			return times;
		})
		.catch((err) => {
			if (times > 0) {
				return retry2(fn, times);
			}
			return Promise.reject(err);
		});
}

@huangzhiyang166
Copy link

/**
  * 
  * @param {function} fn 请求后端接口的方法
  * @param {number}   times 重试次数
  * @param {function} retryCondition 触发重试的条件
  * @returns {function}
  */
 function withRetry(fn,times=3,retryCondition){
	return function(){
		const args = Array.prototype.slice.call(arguments);
		return new Promise((resolve,reject) => {
			doRequest(resolve,reject);
			function doRequest(resolve,reject){
				fn.apply(null,args).then((res) => {
					if(!retryCondition(res)) return resolve(res);
					if(times==0) return reject(res);
					times--;
					doRequest(resolve,reject);
				}).catch(e=>{
					if(times==0) return reject(e);
					times--;
					doRequest(resolve,reject);
				})
			}
		})
	}
}

@jasonzhouu
Copy link

jasonzhouu commented Apr 10, 2021

  • 如果可以用 async await 的话,那么可以用 while 循环,通过同步的语法实现
  • 如果不能用 async await 的话,那么可以用 Promise 递归调用的方法实现

如果要求两次请求间隔一段时间,用 promise 会更方便

在外层使用 async

Promise.retry = async function (fn, times = 3) {
  while (true) {
    console.log(times);
    times--;
    try {
      const res = await fn();
      return res;
    } catch (error) {
      if (times === 0) throw error;
    }
  }
};

在内层使用 async

Promise.retry = function (promiseFn, times = 3) {
  return new Promise(async (resolve, reject) => {
    while (true) {
      console.log(times);
      times--;
      try {
        var ret = await promiseFn();
        resolve(ret);
        break;
      } catch (error) {
        if (times === 0) {
          reject(error);
          break;
        }
      }
    }
  });
};

使用 promise

Promise.retry = function (fn, times = 3) {
  return new Promise(function (resolve, reject) {
    function retry() {
      console.log(times);
      times--;
      fn()
        .then(resolve)
        .catch((error) => {
          if (times === 0) {
            reject(error);
          } else {
            retry();
          }
        });
    }
    retry();
  });
};

@haipingzi
Copy link

 Promise.retry = function (callback) {
      return new this(callback)
        .then((res) => {
          return res;
        })
        .catch(() => {
          return new this(callback);
        });
    };

 Promise.retry((resolve, reject) => {
      setTimeout(() => {
        const nub = Math.random();
        console.log(nub);
        nub > 0.5 ? resolve(nub) : reject(nub);
      }, 1000);
    }).then(
      (res) => {
        console.log("res", res);
      },
      (err) => {
        throw err;
      },

@haipingzi
Copy link

 Promise.retry = function (callback, count = 1) {
      const retryHandle = () => {
        return new this(callback)
          .then((res) => {
            return res;
          })
          .catch((error) => {
            count--;
            console.log(count);
            if (count <= 0) {
              return this.reject(error);
            } else {
              return retryHandle();
            }
          });
      };
      return retryHandle();
    };

    Promise.retry((resolve, reject) => {
      setTimeout(() => {
        const nub = Math.random();
        console.log(nub);
        nub > 0.5 ? resolve(nub) : reject(nub);
      }, 1000);
    }, 5).then(
      (res) => {
        console.log("res", res);
      },
      (err) => {
        throw err;
      },
    );

@chengruixin
Copy link

image

@WebXiaoMing
Copy link

使用生成器实现

Promise.retry = function (promiseFunc, times = 3) {
  return new Promise((resolve, reject) => {
    function * gen () {
      let ret = yield promiseFunc()
      while (times --) {
        ret = yield promiseFunc()
      }
      return ret
    }

    const iterator = gen()

    const onFulfilled = (res) => resolve(res)

    const onRejected = (err) => {
      let ret = iterator.next()
      if (ret.done) {
        return reject(err)
      }
      next(ret)
    }

    const next = (ret) => ret.value.then(onFulfilled, onRejected)

    next(iterator.next())
  })
}

@poppydani
Copy link

Promise.retry = function (promiseFun, times = 5) {
  return new Promise((resolve, reject) => {
    const getResult = () => {
      times --;
      promiseFun().then(res => {
        console.log(res)
        resolve(res);
      }).catch(error => {
        console.log(error)
        if (times <= 0) {
          reject(error);
        } else {
          getResult();
        }
      });
    }
    getResult();
  })
}
Promise.retry(async () => {
  const randomNum = Math.random() - 0.9;
  if (randomNum > 0) {
    return `success: ${randomNum}`;
  } else {
    return Promise.reject(`fail: ${randomNum}`)
  }
})

@dogfeeling
Copy link

直接递归处理

Promise.retry = function (promiseFn, times = 3) {
  return new Promise((resolve,reject)=>  promiseFn().then(res=>resolve(res)).catch(err=>times ? Promise.retry(promiseFn, times-1) : reject(err)))
}

@W-Ace
Copy link

W-Ace commented Feb 15, 2022

Solution using recursion

Promise.retry = (func, times = 3) => {
  return new Promise(async (resolve, reject) => {
    try {
      await func();
      resolve();
    } catch(e) {
      times--;
      if (!times) reject();
      else Promise.retry(func, times);
    }
  })
}

const execute = (str) => {
  console.log(str);
  return new Promise((resolve, reject) => {
    setTimeout(() =>  Math.random() > 0.5 ? resolve() : reject(), 500);
  })
}

Promise.retry(execute.bind(null, 'execute'));

@listentolife
Copy link

listentolife commented Feb 15, 2022 via email

@Yxgm
Copy link

Yxgm commented May 31, 2022

Promise.retry = function (promiseFn, times = 3) {
  //success resolve, else try times
  let count = times;
  let promise = promiseFn;

  return new Promise((resolve, reject) => {
    _retry(resolve, reject);

    function _retry(resolve, reject) {
      promise().then(
        (res) => resolve(res),
        (err) => {
          if (count == 0) return;
          
          count--;
          console.log('重新尝试连接');
          _retry(resolve, reject);
        }
      );
    }
  });
};

function getProm() {
  const n = Math.random();
  return new Promise((resolve, reject) =>
    setTimeout(() => (n > 0.9 ? resolve(n) : reject(n)), 1000)
  );
}

try {
  Promise.retry(getProm).then(
    (res) => console.log(res),
    (err) => console.log(err)
  );
} catch (e) {
  console.log(e);
}

@lucaslmlok
Copy link

Promise.retry = (promiseFn, tries = 3) => {
  return new Promise(async (resolve, reject) => {
    while (tries > 0) {
      tries--;
      try {
        const result = await promiseFn();
        resolve(result);
        break;
      } catch (error) {
        if (tries === 0) reject(error);
      }
    }
  });
};

const over70 = () => {
  const n = Math.floor(Math.random() * 100);
  return new Promise((resolve, reject) => {
    setTimeout(() => (n > 70 ? resolve(n) : reject(n)), 10);
  });
};

Promise.retry(over70)
  .then((result) => console.log('then', result))
  .catch((result) => console.log('catch', result));

@listentolife
Copy link

listentolife commented Jun 20, 2022 via email

@imgss
Copy link

imgss commented Aug 2, 2022

function retry(fn, options = {}) {
  let { times = 3 } = options;
  const { delay = 1000 } = options;
  return new Promise((resolve, reject) => {
    const tryOnce = () => {
      fn()
        .then(resolve)
        .catch((err) => {
          times -= 1;
          if (times > 0) {
            console.log('retry', times);
            setTimeout(() => {
               tryOnce();
            }, delay);
            return;
          }
          reject(err);
        });
    };
    return tryOnce();
  });
}

@listentolife
Copy link

listentolife commented Aug 2, 2022 via email

@Yangfan2016
Copy link

Promise.retry = function (fn, count = 3) {
    return new Promise((rs, rj) => {
        const p = function () {
            count--;
            return fn().then(r => {
                rs(r);
            }).catch((e) => {
                if (!count) {
                    rj(e);
                } else {
                    p();
                }
            });
        }
        p();
    });
}


function getProm() {
    const n = Math.random();
    return new Promise((resolve, reject) => {
        console.count('getProm');
        setTimeout(() => n > 0.9 ? resolve(n) : reject(n), 1000);
    });
}
Promise.retry(getProm).then(r => {
    console.log('ok')
}).catch(e => {
    console.log('fail')
});

@vaakian
Copy link

vaakian commented Jan 31, 2023

利用 Promise 的链式特性,1行代码就能解决,无需循环、async:

Promise.retry = (fn, times = 0) => {
  return fn().catch(() => times > 0 ? Promise.retry(fn, times - 1) : Promise.reject())
}

调用测试:

function getRandom() {
  const n = Math.random()
  console.log(n);
  return new Promise((resolve, reject) => {
    setTimeout(() => (n > 0.9 ? resolve(n) : reject(n)), 1000)
  })
}


Promise.retry(getRandom, 2)
  .then(() => console.log('done'))
  .catch(() => console.log('rejected'))

带注释版:

Promise.retry = (fn, times = 0) => {
  return fn().catch((err) => {
    // 继续尝试
    if (times > 0) return Promise.retry(fn, times - 1)
    // 抛出异常
    return Promise.reject(err)
  })
}

@xiaoguoaa
Copy link

function fetchTest(params = {}) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let n = (Math.random() * 10 + 1) | 0;
      console.log('n', n);
      console.log('params', params);
      if (n > 5) {
        reject('error' + n);
      }
      resolve(n);
    }, 1000);
  });
}
Promise.retry = function(fn, times = 3) {
  return new Promise((resolve, reject) => {
    function attempt() {
      fn()
        .then(resolve)
        .catch(err => {
          if (times === 1) {
            reject(err);
          } else {
            times--;
            attempt();
          }
        });
    }
    attempt();
  });
};
Promise.retry(fetchTest.bind(null, { a: 1, b: 2 }))
  .then(res => {
    console.log('res', res);
  })
  .catch(err => {
    console.log('err', err);
  });

@listentolife
Copy link

listentolife commented Mar 15, 2023 via email

@ZegTsai
Copy link

ZegTsai commented Aug 29, 2023

async function retry(fn, num = 5) {
  try {
    const res = await fn();
    console.log("resolve", res);
  } catch (e) {
    num-- &&  retry(fn, num);
  }
}

Promise.retry = retry;

@listentolife
Copy link

listentolife commented Aug 29, 2023 via email

@Dylan0916
Copy link

Promise.retry = (promiseFunc, retryCount = 3) => {
  let count = retryCount;

  const run = async (resolve, reject) => {
    count -= 1;

    try {
      const result = await promiseFunc();

      resolve(result);
    } catch (error) {
      if (count === 0) {
        return reject(error);
      }

      run(resolve, reject);
    }
  };

  return new Promise(run);
};

@Eagle112
Copy link

image

不对啊....

@listentolife
Copy link

listentolife commented Oct 10, 2023 via email

@AChaoZJU
Copy link

AChaoZJU commented Nov 27, 2024

function getProm() {
    const n = Math.random();
    return new Promise((resolve, reject) => {
        setTimeout(() =>  n > 0.5 ? resolve(n) : reject(n), 500);
    });
}

Promise.retry = function (request, retryTimes) {
    return new Promise((resolve, reject) => {
        let count = 0
        const run = () => {
            request().then(value => {
                console.log(value)
                resolve(value)
            }).catch(error => {
                console.log(error)
                if(count >= retryTimes) {
                    reject(error)
                } else {
                    run()
                }
            })
            count += 1
        }
        run()
    })
}


Promise.retry(getProm, 3)
    .then(value => console.log('Success:', value))
    .catch(error => console.log('Failed after retries:', error));


@listentolife
Copy link

listentolife commented Nov 27, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests