【问题标题】:Not able to getting the result in desired sequence while using async-await and promises in nodejs在 nodejs 中使用 async-await 和 promise 时无法以所需的顺序获得结果
【发布时间】:2020-05-28 16:04:06
【问题描述】:

我参考了很多解决方案,但我认为我的情况与我搜索的情况大不相同。
我是 async-await 和 promises 的新手。
我正在使用 MongoDB 数据库在 nodeJS 中创建一个 cron 作业函数。
我有一个名为 'Device' 的表,其中有一个设备列表,现在我有 5 条记录。
我有其他表通过 deviceId 映射到设备表,即 'Location'、'DeviceInfo'、'DailyStatus'强>.
这是我的代码:

// schedule tasks to be run on the server every sec
cron.schedule("*/1 * * * * *", function() { 
async function finalData() { //asyncronously final data
    function findDevices() { //find all devices
      return new Promise(function (resolve, reject) {
        Device.find((error, data) => {
          if (error) {
            reject("error in sending the data");
          } else {
            if (data.length > 0) {
              resolve(data); //get devices list successfully
            } else {
              reject("data length is ! > 0");
            }
          }
        });
      });
    }
    var dataNew = await findDevices().then(function (returnedData) {
        console.log('every second','findDevices')
      returnedData.forEach((element) => { //iteration perform properly
        async function callMyData() {
          var dataSpeed = await Location.findOne(
            { device: element.deviceId },
            function (error, data) {
              if (error) {
                console.log('error',error)
                return next(error);
              } else {
                return data.speed;
              }
            }
          ).sort({ _id: -1 });
          console.log(dataSpeed.speed,'dataSpeed') //first

          var dataIgnition = await DeviceInfo.findOne(
            { device: element.deviceId },
            function (error, data) {
              if (error) {
                console.log('error',error)
                return next(error);
              } else {
                return data.ignition;
              }
            }
          ).sort({ _id: -1 });
          console.log(dataIgnition.ignition,'dataIgnition') //second

          var dataDailyStatus = await DailyStatus.findOne(
            { device: element.deviceId },
            function (error, data) {
              if (error) {
                console.log("error", error);
                return next(error);
              } else {
                 return data.status;
              }
            }
          ).sort({ _id: -1 });
          console.log(dataDailyStatus.status,'dataDailyStatus') //third

        }
        return callMyData().then(function (string) {
          console.log("next iteration"); //after every interation
        });
      });
    });
  }
  finalData().then(function (string) {});
});

我的 cron 工作正常,并且可以正确获取设备记录。
但我无法按照要求获取记录的顺序。
我期待的是:

every second findDevices
0 'dataSpeed'
0 dataIgnition
Idle dataDailyStatus
next iteration
0 'dataSpeed'
1 dataIgnition
Stop dataDailyStatus
next iteration
0 'dataSpeed'
1 dataIgnition
Idle dataDailyStatus
next iteration
0 'dataSpeed'
0 dataIgnition
Stop dataDailyStatus
next iteration
0 'dataSpeed'
1 dataIgnition
Idle dataDailyStatus
next iteration
Finished

我实际得到的是:

every second findDevices
Finished
0 'dataSpeed'
0 'dataSpeed'
0 'dataSpeed'
0 'dataSpeed'
0 dataIgnition
0 'dataSpeed'
1 dataIgnition
1 dataIgnition
0 dataIgnition
1 dataIgnition
Idle dataDailyStatus
next iteration
Stop dataDailyStatus
Idle dataDailyStatus
Stop dataDailyStatus
next iteration
next iteration
next iteration
Idle dataDailyStatus
next iteration

你们能帮我看看如何实现所请求的序列,因为我对 async-await 和 promises 还很陌生。

【问题讨论】:

  • 当调用findOne 时,您传递的是回调而不是使用承诺。您将无法await 结果。
  • 感谢您抽出宝贵的时间@Bergi,我已尝试将 Promise 与 findOne 一起使用,万岁!我得到了结果。
  • 等一下!我得到了 Promise 。对吗?
  • 每秒 findDevices Promise { } 'dataSpeed' Promise { } 'dataIgnition' Promise { } 'dataDailyStatus' Promise { } 'dataSpeed' Promise { } 'dataIgnition' 承诺 { } 'dataDailyStatus' 承诺 { } 'dataSpeed' 承诺 { } 'dataIgnition' 承诺 { } 'dataDailyStatus' 承诺 { } 'dataSpeed ' 承诺 { } 'dataIgnition' 承诺 { } 'dataDailyStatus' 完成

标签: node.js mongodb asynchronous promise async-await


【解决方案1】:

你可以用更简单的代码得到你想要的结果。

我已经用我创建的库 rubico 重写了 finalData。 rubico 删除了很多围绕 Promises 的样板。

const { pipe, fork, tryCatch, switchCase, map, get, gt } = require('rubico')

const identity = x => x

const findDevices = () => new Promise((resolve, reject) => {
  Device.find((err, data) => err ? reject(err) : resolve(data))
})

const getLocationByDeviceID = deviceId => new Promise((resolve, reject) => {
  Location.findOne(
    { device: deviceId },
    (err, data) => err ? reject(err) : resolve(data),
  ).sort({ _id: -1 })
})

const getDeviceInfoByDeviceID = deviceId => new Promise((resolve, reject) => {
  DeviceInfo.findOne(
    { device: deviceId },
    (err, data) => err ? reject(err) : resolve(data),
  ).sort({ _id: -1 })
})

const getDailyStatusByDeviceID = deviceId => new Promise((resolve, reject) => {
  DailyStatus.findOne(
    { device: deviceId },
    (err, data) => err ? reject(err) : resolve(data),
  ).sort({ _id: -1 })
})

const finalData = pipe([
  tryCatch(
    findDevices, // try findDevices()
    () => { throw new Error('error in sending the data') }, // on error, throw a new Error
  ),
  switchCase([
    gt(get('length'), 0), identity, // if data length is greater than 0, send it through (x => x)
    () => { throw new Error('data length is ! > 0') }, // else throw a new Error
  ]),
  map(fork.series([ // for each device, log speed, ignition, dailyStatus in series
    pipe([
      get('deviceId'), // device => device.deviceId
      getLocationByDeviceID, // deviceId => getLocationByDeviceID(deviceId) => location
      get('speed'), // location => location.speed
      x => console.log(x, 'dataSpeed')
    ]),
    pipe([
      get('deviceId'), // get device.deviceId
      getDeviceInfoByDeviceID, // deviceId => getDeviceInfoByDeviceID(deviceId) => deviceInfo
      get('ignition'), // deviceInfo => deviceInfo.ignition
      x => console.log(x, 'dataIgnition')
    ]),
    pipe([
      get('deviceId'), // get device.deviceId
      getDailyStatusByDeviceID, // deviceId => getDailyStatusByDeviceID(deviceId) => dailyStatus
      get('status'), // dailyStatus => dailyStatus.status
      x => console.log(x, 'dataDailyStatus')
    ]),
  ])), // [device] => [{ speed, ignition, status }]
])

cron.schedule('*/1 * * * * *', finalData)

【讨论】:

  • 感谢@richytong,但您提到的库出现错误。 const mapAsyncIterable = (fn, x) => (async function*() { ^ SyntaxError: Unexpected token * Please guide
  • 你使用的是什么版本的节点?
  • 你至少需要节点v10.3
  • 我已经安装了我的节点 v8.9.0。
  • 你能升级吗?
猜你喜欢
  • 1970-01-01
  • 2020-02-13
  • 1970-01-01
  • 1970-01-01
  • 2021-04-27
  • 2021-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多