异步将数据推送到节点中的数组

时间:2017-05-14 12:41:18

标签: node.js mongodb asynchronous

我在另一个mongoose查询中调用mongoose查询。当我将结果推送到数组时,我最后检查它是否为空。经过大量的搜索后,发现问题是这是异步执行的。但无法找到如何解决问题。我的代码如下。

    Bus.find().exec(function(err,buses) {

        if(err)
            console.log(err);
        if (buses[0] != null){
            const cords = [];
            buses.forEach( function (bus) {
                // console.log(bus);
                    Position.findOne({"busId": bus.busId},{}, {sort : {'time' : -1}}, function (err, position) {
                        cords.push(position);
                        console.log(cords);
                        // console.log(position);
                    });
                    console.log(cords);
                },
                function (err) {
                    if (err){
                        console.log(err,"Errrrrrrrrrrrrr");
                    }
                });
            console.log(cords);
            res.json({cords: cords});
            }

1 个答案:

答案 0 :(得分:2)

嗯,您的代码存在许多问题,但其中最主要的一点是,您无法保存或处理回调内部回调之外的任何值。你的例子(为了清楚起见重写):

var result = []
arry.forEach(function(opt) {
  async.call(args, function(err,value) {
    result.push(value)
  })
})
// result is empty here!

由于您无法知道内部回调何时完成,因此无法正常工作。

根据定义,回调将在未来的某个时间触发,并且由于您无法知道何时,您必须使用传递给回调的结果进行所有计算 在回调本身!

否则会给你不一致的结果。

更新 - 重新评论

(注意:乘坐火车时在iPad上匆匆键入,如果需要,将在稍后修复。

最好的方法是使用Promises来聚合结果。这是一个天真的例子:

/* 
 * given a value and an optional array (accum),
 * pass the value to the async func and add its result to accum
 * if accum is not an array, make it one
 * return accum
 */

var do_something = (value, accum) => {
  // on first pass, accum will be undefined, so make it an array
  accum = Array.isArray(accum) ? accum : []
  return new Promise((resolve, reject) => {
    async_func(value, (err, res) => {
      if(err) {
        reject(err)
      }
      accum.append(res)
      resolve(accum)
    })
  })
}   

/* 
 * for each member of input array, apply do_something
 * then operate on accumulated result.
 */

Promise.map(input, do_something)
  .then(results => {
    // results will contain the accumulated results from all
    // the mapped operations
  })
  .catch(err => {
    throw err
  })

更新 - 每条评论

仅使用回调,您可以使用以下方法获得相同的结果:

const inputs = [...] // array of inputs to pass to async function

const expected_num_of_results = inputs.length

let results = []

const onComplete = (results) => {
  // do something with completed results here
  console.log(`results: ${results}`);
}

const onResult = (err, res) => { // callback to async_func
  if(err) {
    throw new Error(`on iteration ${results.length+1}: ${err}`)
  }

  results.push(res) // save result to accumulator

  if( results.length >= expected_num_of_results) { // are we done?
    onComplete(results) // process results
  }
}

// example async func - REPLACE with actual async function
const async_func = (val,cb) => {
  // call callback with no error and supplied value multiplied by 2
  cb(null,val*2)
}

// wrapper that takes one value 
// and calls async_func with it and predefined callback
const do_async = (value) => { 
  async_func(value, onResult)
}

// process inputs
inputs.forEach(do_async)

所以:

const inputs = [1,2,3,4,5]

将打印:

results: 2,4,6,8,10