Node.js中函数执行出错时如何重新调用该函数?
在Node.js中处理函数执行错误并重试的方案
嘿,针对你提出的「函数执行出错时如何重新调用」的问题,我结合你给出的代码示例,整理了一套实用的解决方案,主要围绕封装通用重试逻辑来处理异步操作的错误重试:
一、先封装一个通用的回调风格重试工具函数
因为你的代码里用的是回调式的异步API(比如client.getAllOffers和connection.query),我们可以写一个通用工具函数来帮我们自动处理重试,不用每个函数都写重复的逻辑:
// 通用重试函数:包裹回调风格的异步函数,支持自动重试 function retryAsync(fn, args, maxRetries = 3, delay = 1000, currentRetry = 0) { return new Promise((resolve, reject) => { // 调用目标异步函数 fn(...args, (err, result) => { if (err) { // 判断是否还有重试次数 if (currentRetry < maxRetries) { console.log(`操作失败,${delay}ms后进行第${currentRetry + 1}次重试 | 错误信息:${err.message}`); // 延迟后递归调用重试 setTimeout(() => { retryAsync(fn, args, maxRetries, delay, currentRetry + 1) .then(resolve) .catch(reject); }, delay); } else { // 重试耗尽,抛出最终错误 reject(new Error(`已重试${maxRetries}次仍失败,终止操作:${err.message}`)); } } else { // 操作成功,返回结果 resolve(result); } }); }); }
二、改造你的业务代码,接入重试逻辑
接下来我们把原代码里的异步操作都用这个重试函数包裹,同时改用async/await让代码更易读(避免回调地狱):
app.get('/', async function (req, res) { try { // 对getAllOffers接口调用应用重试逻辑(最多重试3次,间隔1.5s) const resp = await retryAsync(client.getAllOffers, [null], 3, 1500); const offer = JSON.parse(resp); const offerCount = offer.allOffersList.length; res.send(offer); // 遍历插入数据库,每个插入操作都加重试 for (let i = 0; i < offerCount; i++) { const stmt = "INSERT INTO offers(description,start_time,end_time) VALUES (?, ?, ?)"; const insertParams = [ offer.allOffersList[i].description, offer.allOffersList[i].startTime, offer.allOffersList[i].endTime ]; // 数据库插入最多重试2次,间隔1s await retryAsync(connection.query, [stmt, insertParams], 2, 1000); console.log(`第${i + 1}条优惠记录插入成功`); } } catch (err) { // 捕获所有最终失败的错误,返回给客户端 console.error('操作最终失败:', err); res.status(500).send('服务器内部错误,请稍后重试'); } });
三、进阶优化建议
- 区分可重试错误:不是所有错误都值得重试,比如SQL语法错误、参数错误这类永久错误,重试多少次都没用。你可以在重试函数里加错误判断:
// 在retryAsync的err分支里添加判断 const retryableErrors = ['network', 'timeout', 'connection']; const isRetryable = retryableErrors.some(keyword => err.message.includes(keyword)); if (isRetryable && currentRetry < maxRetries) { // 只重试临时错误 setTimeout(/* 重试逻辑 */); } else { reject(err); // 非重试错误直接抛出 } - 指数退避策略:可以把重试间隔改成指数增长(比如1s→2s→4s),避免短时间内频繁请求给服务造成压力:
setTimeout(() => { retryAsync(fn, args, maxRetries, delay * 2, currentRetry + 1) .then(resolve) .catch(reject); }, delay); - 避免并发问题:如果你的插入操作很多,也可以考虑用批量插入或者控制并发数,避免同时发起大量数据库请求。
内容的提问来源于stack exchange,提问作者Anandh
相关产品推荐
相关产品推荐

