修复executeNextBatch()未始终返回Promise的Node.js异步问题
问题解决:Promise调用时出现undefined错误
问题场景
实现了一个物品列表遍历函数:若数据库存在物品对应图片则直接赋值,不存在则调用OpenAI生成图片并保存至数据库。图片生成与保存功能正常,但调用函数时触发TypeError: Cannot read properties of undefined (reading 'then')错误,错误指向executeNextBatch().then(...)代码行。已知混用then与await语法,核心问题是executeNextBatch()并非始终返回Promise,需在保留批量请求限制的前提下修复。
错误原因
executeNextBatch()函数在index >= batches.length(所有批次执行完成)时,未返回任何值(默认返回undefined),而undefined不存在.then()方法,导致调用时报错。
修复方案
修改executeNextBatch(),当所有批次执行完成后返回一个已resolved的Promise:
function executeNextBatch() { if (index < batches.length) { return executeBatch(batches[index++]) .then(() => new Promise(resolve => setTimeout(resolve, 60000 / MAX_REQUESTS_PER_MINUTE))) .then(executeNextBatch); } // 新增:所有批次完成后返回resolved的Promise return Promise.resolve(); }
额外优化点
1. generateImageByNameAndSave函数错误处理优化
- 混用
await与.catch()会导致错误被吞掉,建议统一用try/catch处理:// 替换原await + .catch写法 let newImage; try { newImage = await openai.images.generate({ prompt: imageName, response_format: 'b64_json', n: 1, size: "256x256", },{ validateStatus: function (status) { return status < 500; } }); } catch(e) { console.log('imageName ' + JSON.stringify(imageName)); console.log('e ' + JSON.stringify(e)); if (e.data.error.message.includes('safety system')) { throw new Error('图片生成被安全系统拦截'); } console.error(e); throw e; } image.save(image)参数冗余,save()方法无需传入自身,直接await image.save()即可- 重复赋值
image.merchantId,删除重复代码行
2. findImagesForObjectsOrGenerate函数可读性优化
改为async函数,用await替代then()让代码更直观:
async function findImagesForObjectsOrGenerate(listOfObjects, images, isCategory, merchantId) { const MAX_REQUESTS_PER_MINUTE = 1; const requestsPerBatch = Math.min(MAX_REQUESTS_PER_MINUTE, listOfObjects.length); let promises = []; if (listOfObjects.length > 0) { listOfObjects.forEach((object) => { const matchedImage = images.find(image => object.id === image.cloverDataId); if (matchedImage) { object.imageData = matchedImage.imageData; } else { promises.push(() => imageService.generateImageByNameAndSave(object.name, isCategory, object.id, merchantId)); } }); } function executeBatch(batch) { return Promise.all(batch.map(fn => fn())); } const batches = []; while (promises.length > 0) { batches.push(promises.splice(0, requestsPerBatch)); } let index = 0; async function executeNextBatch() { if (index < batches.length) { await executeBatch(batches[index++]); await new Promise(resolve => setTimeout(resolve, 60000 / MAX_REQUESTS_PER_MINUTE)); await executeNextBatch(); } } await executeNextBatch(); return listOfObjects; }
内容的提问来源于stack exchange,提问作者coder123
相关产品推荐
相关产品推荐

