关于异步函数中保存回调数据的问题

为什么console.log(theFile)能输出数据,而不能保存到dateArray数组中。
如果要保存到dataArray数组中,是不是也要构造一个异步函数

code

        var dataArray = [];
        for(let i = 0; i < files.iconImage.length; i++) {
            // var iconFile = files.iconImage[i];
            if(files.iconImage[i].size !== 0){
              fs.readFile(files.iconImage[i].path, function(err, data){
                if(err) {
                  return res.send('读取文件失败');
                }
                var theFile = new AV.File(files.iconImage[i].originalFilename, data);
                theFile.save().then(function(theFile){
                  console.log(theFile);
                  dataArray.push(theFile);
                }).catch(console.error);
              });
            } else {
              res.send('请选择一个文件。');
            }
        }
        res.json({
            success: true,
            data: dataArray
        })
      });
阅读 3.5k
3 个回答

谢邀,可以使用 Promse.all 获取所有数据,并在 then 里 res.json

思路供参考

Promise.all(
  files.iconImage
  .filter(icon => icon.size !== 0)
  .map(icon => new Promise((resolve, reject) => {
    fs.readFile(icon.path, (err, data) => {
      if (err) { return reject('读取文件失败') }
      resolve(new AV.File(icon.originalFilename, data).save())
    })
  }))
)
.then(dataArray => res.json({success: true, data: dataArray}))
.catch(error => res.send(error))

首先,楼主的代码里问题有几处问题:

  1. var theFile = new AV.File(files.iconImage[i].originalFilename, data);,在异步回调里,i最终取到的都是files.iconImage.length - 1,因此new AV.File()的初始化会有问题,最终的dataArray也会有问题。
  2. return res.send('读取文件失败');,如果不止一个文件读取失败,res.send()会被调用多次,导致服务端报错。
  3. theFile变量重名了。

根据楼主的需求修改后的代码:(未经严格测试,楼主参考着修改即可)

// 封装readFile,将异步操作转成promise
var readFile = function(iconImage, index) {
  return new Promise(function (resolve, reject) {
    fs.readFile(iconImage.path, function(err, data) {
        if (err) {
            reject(new Error(读取文件失败));
            return;
        }

        var theFile = new AV.File(iconImage.originalFilename, data);
        theFile
          .save()
          .then(function(_theFile) {
            resolve(_theFile);
          })
          .catch(function (e) {
            reject(e);
          });
    });
  });
};

var shouldChooseFile = files.iconImage.some(function (iconImage) {
  return iconImage.size === 0;
});

if(shouldChooseFile) {
  res.send('请选择一个文件。');
  return;
}

// 转成promise数组,具体自行查看 Promise.all(array) 的用法
var reqArr = files.iconImage.map(readFile);

Promise
  .all(reqArr)
  .then(function (dataArray) {
    res.json({
        success: true,
        data: dataArray
    });
  })
  .catch(function (e) {
    // 楼主自行错误处理
  });

你这个 for 循环中的readFile  是个异步的方法。所以res.json 会先执行的,而这时候你的dataArray还没有push 进去数据的。你把res.json方法放到dataArray.push(theFile);之后就可以了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题