NodeJS在返回之前从异步回调构造数组

时间:2017-08-29 12:36:30

标签: node.js express asynchronous

我正在编写一个返回值和数组的函数。某些值是在回调中计算的。但我不知道如何使程序异步,所以我的所有结果都在数组中,并且在返回后不会添加。

let array = [] 
for (stuff : stuffs) {
  if (condition) {
     array.add(stuff)
  } else {
     api.compute(stuff, callback(resp) {
          array.add(resp.stuff)
     }
  }
}
res.json({ "stuff": array })

在此示例中,在异步调用完成之前,数组将写入响应。

如何异步进行此操作?

2 个答案:

答案 0 :(得分:1)

您必须使用以下方法之一:

  • async library
  • Promise.all
  • 协程/发电机
  • 异步/ AWAIT

我认为最酷的是async/await。首先我们修改你的函数,所以它返回一个promise:

const compute = function(stuff) {
  return new Promise( (resolve, reject) => {
    api.compute(stuff, callback(resp){
      resolve(resp.stuff)
    });
  });
};

然后我们使用异步处理程序修改您的路由:

app.get('/', async function(req, res, next) {
  const array = [];
  for (const stuff of stuffs) {
    if (condition) {
      array.add(stuff);
    } else {
      const stuff = await compute(stuff);
      array.push(stuff);
    }
  }
  res.json({ stuff: array });
});

注意:您可能需要将节点版本更新为最新版本。

<强>更新

那些不知道的人,事件循环如何工作,执行这个片段,然后完成:

const sleep = async function(ms) {
  console.log(`Sleeping ${ms}ms`);
  return new Promise( resolve => setTimeout(resolve, ms));
};

async function job() {
  console.log('start');

  for (let t = 0; t < 10; t++) {
    await sleep(100);
  }
}

job();

console.log('oops did not expect that oO');

你会感到惊讶。

答案 1 :(得分:1)

这是一个没有使用回调的包的答案

创建一个能递归处理所有内容的功能。

getArray(stuffs, callback, index = 0, array = []) {
  // Did we treat all stuffs?
  if (stuffs.length >= index) {
    return callback(array);
  }

  // Treat one stuff
  if (condition) {
    array.add(stuffs[index]);

    // Call next
    return getArray(stuffs, callback, index + 1, array);
  }

  // Get a stuff asynchronously
  return api.compute(stuffs[index], (resp) => {
    array.add(resp.stuff);

    // Call next
    return getArray(stuffs, callback, index + 1, array);
  });
}

怎么称呼它?

getArray(stuffs, (array) => {
   // Here you have your array
   // ...
});

编辑:更多解释

我们想要做的是将你所拥有的循环转换为处理异步函数调用的循环。

目的是一个getArray调用将处理stuffs数组的一个索引。

在处理了一个索引之后,该函数将再次调用自身来处理下一个索引,直到所有索引都被处理完毕。

-> Treat index 0 -> Treat index 1 -> Treat index 2 -> Return all result

我们正在使用参数在整个过程中传递信息。 Index知道我们必须处理哪个数组部分,并array保留我们计算的数据。

编辑:改进100%异步解决方案

我们在这里所做的是将初始for循环简单转换为异步代码。它可以通过使它完全异步来改进,这使它变得更好但稍微更难。

例如:

// Where we store the results
const array = [];

const calculationIsDone = (array) => {
  // Here our calculation is done
  // ---
};

// Function that's gonna aggregate the results coming asynchronously
// When we did gather all results, we call a function
const gatherCalculResult = (newResult) => {
  array.push(newResult);

  if (array.length === stuffs.length) {
    callback(array);
  }
};

// Function that makes the calculation for one stuff
const makeCalculation = (oneStuff) => {
  if (condition) {
    return gatherCalculResult(oneStuff);
  }

  // Get a stuff asynchronously
  return api.compute(oneStuff, (resp) => {
    gatherCalculResult(resp.stuff);
  });
};

// We trigger all calculation
stuffs.forEach(x => x.makeCalculation(x));