首页 > 解决方案 > 如何从异步每个函数返回值?

问题描述

我知道这对人们来说是一个常见问题,我查阅了一些指南并查看了文档,但我不明白发生了什么,希望得到一些帮助。

这是我正在处理的控制器功能:

exports.appDetail = function (req, res) {
  appRepo.findWithId(req.params.id, (err, myApp) => {
    if (err) {
      console.log(err)
    }
    getDeviceData(myApp.devices, (err, myDeviceData) => {
      if (err) console.log(err)
      console.log(JSON.stringify(myDeviceData) + '  ||  myDeviceData')
      // construct object to be returned
      let appsDataObject = {
        name: myApp.name,
        user_id: myApp.user_id,
        devices: myDeviceData,
        permissions: myApp.permissions
      }
      return res.status(200).send(appsDataObject)
    })
  })
}

// write async function here
const getDeviceData = function (devices, callback) {
  let devicesDataArray = []
  async.each(devices, function (device, cb) {
    deviceRepo.findById(new ObjectID(device), (err, myDevice) => {
      if (err) {
        cb(err)
      }
      // get device data, push to devices array
      let deviceObj = {
        name: myDevice.name,
        version: myDevice.version
      }
      devicesDataArray.push(deviceObj)
      console.log(JSON.stringify(devicesDataArray) + '  ||  devicesDataAray after obj push')
    })
    cb(null, devicesDataArray)
  }, function (err) {
    // if any of the file processing produced an error, err would equal that error
    if (err) console.log(err)
  })
  callback(null, devicesDataArray)
}

我最初是用 for 循环和回调编写的,但我认为这样做是不可能的(不过我不确定)。如果有更好的方法来制作异步循环,请告诉我。

在〜第 8 行有一个日志语句myDeviceData。这应该通过回调返回我想要的数据,但是这个日志语句总是返回空。而且由于其他日志语句显示数据格式正确,因此问题一定是通过getDeviceData(). 据推测,callback(null, devicesDataArray)应该这样做。

我不明白这些异步函数应该如何工作,很清楚。有人可以帮我理解我应该如何从这些 async.each 函数中获取值吗?谢谢你。

编辑:我重构了代码以尝试使其更清晰并更好地解决问题,并且我已经确定了问题所在。一开始我将这个函数定义devicesDataArray为一个空数组,最后我返回这个数组。里面的一切都按原样发生,但我不知道如何告诉 return 等到数组不为空,如果这有意义的话,这是新代码:

let getData = async function (devices) {
  let devicesDataArray = []
  for (let i = 0; i < devices.length; i++) {
    deviceRepo.findById(new ObjectID(devices[i]), async (err, myDevice) => {
      if (err) {
        console.log(err)
      }
      console.log(JSON.stringify(myDevice) + '  ||  myDevice')
      let deviceObj = await {
        name: myDevice.name,
        version: myDevice.version
      }
      console.log(JSON.stringify(deviceObj) + '  ||  deviceObj')
      await devicesDataArray.push(deviceObj)
      console.log(JSON.stringify(devicesDataArray) + '  ||  devicesDataArray after push')
    })
  }
  console.log(JSON.stringify(devicesDataArray) + '  ||  devicesDataArray before return')
  return Promise.all(devicesDataArray)  // problem is here.
}

感谢您对理解这一点的任何帮助。

标签: javascriptnode.jsasynchronousasync.js

解决方案


这里我们使用Promise

Promise对象立即返回,我们在那里执行我们的异步代码。

const someFuncThatTakesTime = () => {
  // Here is our ASYNC 
  return new Promise((resolve, reject) => {
    // In here we are synchronous again. 
    const myArray = [];  
    for(x = 0; x < 10; x++) {
      myArray.push(x);
    }
    
    // Here is the callback    
    setTimeout(() => resolve(myArray), 3000);  
  });
};

someFuncThatTakesTime().then(array => console.log(array));


推荐阅读