Node.js异步图片下载时Promise数组处于pending状态的问题求解
问题解决方法
问题根源
你当前代码中imagePaths数组存储的是刚创建的异步下载任务对应的Promise实例,for循环仅负责创建异步任务,不会等待任务执行完毕,所以直接打印时所有Promise都处于pending状态,无法拿到实际下载后的文件路径。
修复方案
使用Promise.all()等待所有下载任务全部执行完成后,再执行后续逻辑。同时你现有代码存在两处隐性问题需要同步修复:
- 自定义
download方法的回调参数顺序不符合Node.js错误优先的回调规范,参数顺序写反会导致错误捕获失效 - 保存文件时给文件名拼接了根据content-type生成的后缀,但resolve返回的是不带后缀的原始文件名,后续使用该路径会找不到文件,需要同步修正
修正后的核心代码
Template.findOne({ templateId: template_id }).exec() .then(template => { if (imageURLs.length !== template.requiredImages.count) { res.status(422).json({ status: "Fail", message: "This template needed " + template.requiredImages.count + " image. But received " + imageURLs.length }) // 终止后续Promise链执行,避免重复返回响应报错 return Promise.reject('参数校验不通过') } else { return template; } }) .then(template => { function naming(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for (var i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } var download = function (uri, filename, callback) { request.head(uri, function (err, res, body) { if(err) return callback(err) console.log('content-type:', res.headers['content-type']); console.log('content-length:', res.headers['content-length']); const ext = res.headers['content-type'].split('/')[1] const fullFilename = filename + '.' + ext request(uri).pipe(fs.createWriteStream(fullFilename)).on('close', () => { // 返回带后缀的完整文件路径 callback(null, fullFilename) }); }); }; var downloadTasks = []; for (const imageURL of imageURLs) { downloadTasks.push(new Promise((resolve, reject) => { let filename = __dirname + '/../../../downloads/' + naming(6) download(imageURL, filename, function (err, fullFilename) { if (err) reject(err); else resolve(fullFilename) }); })) } // 批量等待所有下载任务完成 return Promise.all(downloadTasks) }) .then(imagePaths => { // 所有任务执行完成后才会进入该回调,imagePaths为下载完成的文件路径数组 console.log(imagePaths); res.json("oki"); }) .catch(err => { // 统一捕获所有环节的错误 console.error('处理出错:', err) if(!res.headersSent) { res.status(500).json({status: 'Fail', message: '处理失败'}) } })
内容的提问来源于stack exchange,提问作者Süleyman Ali Akpınar
相关产品推荐
相关产品推荐

