使用promises生成数据集

时间:2017-10-23 20:23:56

标签: javascript node.js callback bluebird

我目前正在尝试使用javascript中的异步调用生成一对数组但是我似乎无法以正确的顺序获取它。

generateDataPoints: function (iterable, source, arg) {
  let pairs = []
  let prevTime = 0
  for (let index in iterable) {
    let event = iterable[index]
    getTime(event.valueOf()).then(function (time) {
      query(source[arg], event.valueOf()).then(function(val) {
        if (time !== prevTime) {
          prevTime = time
          pairs.push([time, val])
          console.log(pairs) // This works as expected but only happens after the program returns
        } else {
          Promise.resolve()
        }
      })
    })
  }
  return Promise.resolve(pairs)
}

问题在于" pairs.push .."命令发生在我返回后。我无法弄清楚到底出了什么问题,以及如何同步这个过程。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

您正在使用异步代码混合同步代码(如for循环)。尝试这样的事情:

function generateDataPoints(iterable, source, arg) {
  let prevTime = 0
  [...iterable].reduce((promiseChain, event) => {
    let pairs;
    return promiseChain
      .then(p => {
        pairs = p;
        return Promise.all([
          getTime(event.valueOf()),
          query(source[arg], event.valueOf())
        ])
      })
      .then(([time, val]) => {
        if (time !== prevTime) {
          prevTime = time
          return pairs.concat([[time, val]]);
        } else {
          return pairs;
        }
      });
    })
  }, Promise.resolve([]));
}

这会将iterable缩减为顺序的Promise链,最终将包含所有对。

如果您的环境允许,您还可以将您的功能转换为 async 功能,只需进行少量更改:

generateDataPoints: async function (iterable, source, arg) {
  let pairs = []
  let prevTime = 0
  for (let index in iterable) {
    let event = iterable[index]
    const [time, val] = await Promise.all([
      getTime(event.valueOf()),
      query(source[arg], event.valueOf())
    ]);
    if (time !== prevTime) {
      prevTime = time
      pairs.push([time, val])
    }
  }
  return pairs;
}

修改

仔细看,看起来你需要对这些Promise进行序列化。您也许可以并行运行它们:

function generateDataPoints(iterable, source, arg) {
  Promise.all(
    [...iterable].map(event => Promise.all([
      getTime(event.valueOf()),
      query(source[arg], event.valueOf())
    ])
  ).then(pairs => {
    let prevTime = 0
    return pairs.filter(([time, val]) => {
      if (time !== prevTime) {
        prevTime = time;
        return true;
      } else {
        return false;
      } 
    });
  });
}