运行3个承诺,然后在其他承诺完成后运行最后的承诺

时间:2017-05-12 05:55:39

标签: javascript node.js promise

我正在编写nodejs控制器。

我有一整套承诺,每个承诺都会从不同的查询中获取数据

我想要启动它们(因为它们需要不同的时间才能完成),一旦它们全部完成,那么我想启动priceCalc函数,它使用所有收集的数据。

我查看了许多指南和示例,但我不理解promise.all以及它如何在我的案例中起作用?

此外,如果其中一个失败,它应该返回错误?它们必须全部完成priceCalc功能才能启动。

(我是承诺的新手,所以如果可以的话请尽量简单:-)))

var findPrice = new Promise(
    (resolve, reject) => {
    priceTable.findOne........

var movePrice = function (data) {
    priceArray = data......

findPrice       
    .then(movePrice)
    .then(fulfilled => console.log('findPrice FINISHED!!!'))
    .catch(error => console.log(error.message));        


var findhotdeal = new Promise(
    (resolve, reject) => {
    hotdealTable.aggregate.........

var movehotdeal = function (data) {
    hotdealArray = data;.......     

findhotdeal       
    .then(movehotdeal)
    .then(fulfilled => console.log('findhotdeal FINISHED!!!'))
    .catch(error => console.log(error.message));


var calculatePrice = function () {
    // Use the data from the previous promises once they all finished

}

2 个答案:

答案 0 :(得分:3)

如果您需要所有4个承诺的已解决值

var findPrice = new Promise(
    (resolve, reject) => {
    priceTable.findOne........

var movePrice = function (data) {
    priceArray = data......

var findhotdeal = new Promise(
    (resolve, reject) => {
    hotdealTable.aggregate.........

var movehotdeal = function (data) {
    hotdealArray = data;.......     

var calculatePrice = function ([fp, mp, fh, mh]) {
    // fp == resolved value of findPrice
    // mp == resolved value of movePrice
    // fh == resolved value of findhotdeal
    // mh == resolved value of movehotdeal
}

Promise.all([findPrice, findPrice.then(movePrice), findhotdeal, findhotdeal.then(movehotdeal)])
    .then(calculatePrice)
    .catch(err => { /* handle errors here */})

注意:

var calculatePrice = function ([fp, mp, fh, mh]) {
    // fp == resolved value of findPrice
    // mp == resolved value of movePrice
    // fh == resolved value of findhotdeal
    // mh == resolved value of movehotdeal
}

是ES2015 +

的简写
var calculatePrice = function (r) {
    var fp = r[0],
        mp = r[1],
        fh = r[2],
        mh = r[3];

    // fp == resolved value of findPrice
    // mp == resolved value of movePrice
    // fh == resolved value of findhotdeal
    // mh == resolved value of movehotdeal
}
  

鉴于movePrice和movehotdeal并不是异步

var findPrice = new Promise((resolve, reject) => {
    priceTable.findOne........
});

var findhotdeal = new Promise((resolve, reject) => {
    hotdealTable.aggregate.........
});

var calculatePrice = function ([fp, fh]) {
    priceArray = fp;
    hotdealArray = fh;
    // fp == resolved value of findPrice
    // fh == resolved value of findhotdeal
}

Promise.all([findPrice, findhotdeal])
    .then(calculatePrice)
    .catch(err => { /* handle errors here */})

答案 1 :(得分:1)

原始承诺

我很高兴看到你已经了解了Promise.all,但我认为你可以推断Promise如何运作并理解你可以自己构建这些东西是很重要的。

您原来的标准

  

我有一整套承诺,每个承诺都会从不同的查询中获取数据

     

我想要启动它们(因为它们需要不同的时间才能完成),一旦它们全部完成,那么我想启动priceCalc函数,它使用所有收集的数据。

我们希望我们的代码看起来像下面的

all(arrayOrPromises)
  .then(values => onSuccess(values), err => onFailure(err))

我将首先实施all并解释一下。然后,我将介绍几个其他助手来构建演示,以确保一切按预期工作。

直观地说,all采用 promises 数组,并返回一个解析数组的promise。

// all :: [Promise a] -> Promise [a]
const all = ps =>
  new Promise((resolve, reject) => {
    let pending = ps.length, result = []
    ps.forEach((p,i) => p
      .then(x => result[i] = x)
      .then(() => --pending === 0 ? resolve(result) : null)
      .catch(reject))
  })

我们首先返回一个Promise。当给出N个promises的输入数组时,我们知道在最终解析all返回的promise之前我们需要N个promise才能解决。所以我们所做的就是为已解析的值(result)创建一个容器,将.then附加到存储已解析值的每个promise,并附加一个.then以检查是否我们最终可以解析result - 当pending0时,没有更多待处理的承诺,因此是resolve的时间。最后,我将.catch附加到每个承诺,以便在任何承诺失败的情况下,外部承诺会立即被拒绝

演示助手

要构建演示,我们需要创建一个承诺数组,这些数组需要花费一段时间才能完成。当然你的代码将调用返回promises的实际函数,所以这只是一个模拟 - 我包含这些的原因是all可以作为一个独立的独立演示在这个答案中展示

// fakeP :: a -> Promise a
const fakeP = x =>
  Promise.resolve(x)
    .then(log('start'))
    .then(wait(rand(5000)))
    .then(log('end'))

fakeP以“假”延迟(随机0-5秒)作出承诺。对于添加的可视化,fakeP还将记录承诺启动结束

// eg
fakeP(1).then(console.log, console.error)
// start 1
// <random delay>
// end 1
// 1

logwaitrand不是很有趣,但您可以在下面的代码中阅读其定义

Runnable演示

点击下面的运行查看输出。最重要的是,请注意,尽管承诺以非确定性顺序解决,但解析后的值将按承诺传递的顺序出现

// all :: [Promise a] -> Promise [a]
const all = ps =>
  new Promise((resolve, reject) => {
    let pending = ps.length, result = []
    ps.forEach((p,i) => p
      .then(x => result[i] = x)
      .then(() => --pending === 0 ? resolve(result) : null)
      .catch(reject))
  })

// fakeP :: a -> Promise a
const fakeP = x =>
  Promise.resolve(x)
    .then(log('start'))
    .then(wait(rand(5000)))
    .then(log('end'))

// wait :: Int -> a -> Promise a
const wait = ms => x =>
  new Promise(r => setTimeout(r, ms, x))

// label :: String -> a -> a
const log = label => x =>
  (console.log(label, x), x)

// rand :: Number -> Number
const rand = x =>
  Math.random() * x

// 5 "fake" promises with random delay (0-5 seconds each)
const promises =
  [ fakeP('a'), fakeP('b'), fakeP('c'), fakeP('d'), fakeP('e') ]

// run it
all(promises).then(console.log, console.error)

// start a
// start b
// start c
// start d
// start e
// end e
// end a
// end d
// end c
// end b
// [ 'a', 'b', 'c', 'd', 'e' ]

所以在这里的例子中,我们只是使用console.log作为onSuccess函数

all(promises).then(console.log, console.error)
// ...
// [ 'a', 'b', 'c', 'd', 'e' ]

我们可以用任何东西取而代之,用我们的价值做任何我们喜欢的事情

all(promises).then(
  xs => console.log(xs.reverse().join('').toUpperCase()),
  console.error
)
// ...
// EDCBA

<强>说明

好的,所以当all正是您所需要的并且已经为您提供时,请不要使用Promise.all。我写这篇文章的要点是,当你完成一项任务并且你没有意识到一个神奇地解决你所有问题的一体化功能时,你不必感到无助。

编写自己的函数来解决您的问题,然后在您了解到Promise.all存在后再返回到您的代码,这没有错。