как вернуть значения из асинхронной каждой функции? - PullRequest
0 голосов
/ 05 октября 2019

Я знаю, что это обычная проблема для людей, и я посмотрел некоторые руководства и посмотрел на документы, но я не понимаю, что происходит, и хотел бы помочь.

Здесьэто функция контроллера, над которой я работаю:

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? Спасибо.

РЕДАКТИРОВАТЬ: я переработал код, чтобы попытаться сделать его более понятным и лучше подходить к проблеме, и я точно определил, где проблема. В начале функции this я определяю devicesDataArray как пустой массив, а в конце возвращаю массив. Все внутри происходит так, как должно, но я не знаю, как заставить возврат ждать, пока массив не станет пустым, если это имеет смысл, вот новый код:

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.
}

Любая помощьк пониманию это ценится.

Ответы [ 2 ]

0 голосов
/ 05 октября 2019

Во-первых, я бы предпочел избегать использования обратного вызова, потому что это сделает ваш код нечитаемым, также вы можете обрабатывать async с помощью методов javascript без необходимости использования других модулей. причина вашей проблемы в том, что ваша функция async.each выполняется без ожидания того, что находится внутри
, и у вас есть здесь deviceRepo.findById, которая является асинхронной функцией, и вам нужно дождаться ее. Я реорганизовал ваш код с помощью async await, и мне бы хотелось, чтобы это былоупростить задачу

 exports.appDetail = function async(req, res) {
  try {
    const myApp = await appRepo.findWithId(req.params.id)
    const myDeviceData = await getDeviceData(myApp.device)
    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)
  } catch (err) {
    console.log(err)
  }

}

// write async function here
const getDeviceData = function async(devices) {
  let devicesDataArrayPromises = devices.map(async(device)=>{
  const myDevice=  await deviceRepo.findById(new ObjectID(device))
        let deviceObj = {
        name: myDevice.name,
        version: myDevice.version
      }
  return deviceObj
  })
  const devicesDataArray = await Promise.all(devicesDataArrayPromises)
      console.log(JSON.stringify(devicesDataArray) + '  ||  devicesDataAray after obj push')
return  devicesDataArray
}
0 голосов
/ 05 октября 2019

Здесь мы используем 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));
...