使用Express File Upload的mv方法后fileCheck返回值未触发引发解构报错问题
问题核心原因
- 报错的本质是异步操作的返回值无法向外层函数传递:写在
file.mv回调内部的return语句,作用域仅属于mv方法的回调函数本身,值根本不会回流到外层fileCheck函数的返回值上。 file.mv本身是异步IO操作,调用后不会等待回调执行完成就会直接跳出当前函数体。由于外层fileCheck函数在走到file.mv(...)这行代码后,没有设置任何主动的return逻辑,函数执行完就会默认返回undefined,这就是解构时出现Cannot destructure property 'success' of '(intermediate value)' as it is undefined报错的直接触发点。- JS的异步执行机制决定了,写在回调里的return,和外层调用的函数是完全隔离的两个作用域,根本拿不到预期的返回值。
修复方案
两种常用的落地改法,核心都是把原本拿不到返回值的异步流程,改成可以同步感知结果的结构:
方案1:将fileCheck改造为返回Promise,配合async/await使用
用Promise包裹mv的执行逻辑,让外层可以等待上传操作完成后再拿到对应的返回值:
const fileCheck = ( file ) => { // 外层直接返回Promise对象,让调用方可以等待操作完成 return new Promise((resolve) => { if ( Array.isArray( file ) ) { console.log( 'THE USER WANTS TO UPLOAD MULTIPLE FILES' ); // 按你的多文件业务逻辑补全返回内容即可 resolve({ success: false, message: '暂不支持多文件上传场景', data: null }) return } if ( typeof file === 'object' ) { console.log( 'THE USER WANTS TO UPLOAD A SINGLE FILE' ); const uploadPath = `./resources/images/${file.name}`; file.mv( uploadPath, function ( err ) { if ( err ) { console.error( err ); // 操作完成后通过resolve传递结果,不要依赖回调内部的return resolve({ success: false, message: 'Something went wrong. Please upload again!', data: null }); return } resolve({ success: true, message: 'File Uploaded Successfully!', data: file.name }); }); } else { // 补全无文件场景的边界判断,避免空值引发的报错 resolve({ success: false, message: '未检测到有效上传文件', data: null }) } }) }
调用时要注意,因为返回的是Promise对象,必须加await关键字,且当前的Express路由方法需要用async修饰:
// 路由方法必须加async才能使用await语法 app.post('/upload', async (req, res) => { try { // 等待fileCheck返回结果后再做解构 const { success, message, data } = await fileCheck(req.files.fileInput); console.log( success ); // 后续接口返回逻辑 res.json({ success, message, data }) } catch (err) { res.status(500).json({ success: false, message: '服务处理异常', data: null }) } })
方案2:保留原有回调结构,不使用Promise/await
如果不想改异步语法,可以直接把结果通过回调函数向外传递,不要试图从fileCheck函数拿返回值:
const fileCheck = ( file, resultCallback ) => { if ( Array.isArray( file ) ) { console.log( 'THE USER WANTS TO UPLOAD MULTIPLE FILES' ); resultCallback({ success: false, message: '暂不支持多文件上传场景', data: null }) return } if ( typeof file === 'object' ) { console.log( 'THE USER WANTS TO UPLOAD A SINGLE FILE' ); const uploadPath = `./resources/images/${file.name}`; file.mv( uploadPath, function ( err ) { if ( err ) { console.error( err ); // 直接把处理结果传给自定义的回调函数 resultCallback({ success: false, message: 'Something went wrong. Please upload again!', data: null }); return } resultCallback({ success: true, message: 'File Uploaded Successfully!', data: file.name }); }); } else { resultCallback({ success: false, message: '未检测到有效上传文件', data: null }) } }; // 调用时直接传入回调函数处理结果 fileCheck(req.files.fileInput, (result) => { const { success, message, data } = result; console.log( success ); // 在这里写后续的接口返回、业务处理逻辑 })
内容的提问来源于stack exchange,提问作者s.khan
相关产品推荐
相关产品推荐

