产生多重承诺

时间:2017-07-24 21:54:42

标签: javascript node.js promise es6-promise

我不确定这是可能的,但这正是我想要做的。我调用了一个返回promise的数据库。在then我想迭代结果并为每一行产生一个新的承诺来发出HTTP请求。它正在执行所有HTTP请求,但我无法为每个请求链接一个。这是我尝试过的:

尝试1

userDao.getBitbucketInfoForUser(token.id, cohortId)
    // Get Bitbucket information and make clones
    .then((teams) => {
        for(const team of teams) {
            console.log('Clone repo ' + sourceRepo + ' for Team-' + team.teamNumber);
            return makeFork(gitInfo, sourceRepo, team);
        }
    })
    .then((result) => {
        const team = result.team;
        console.log('Wait for Team ' + team + ' repo');
    })
    .catch((error) => {
        console.log(error);
        response.status(error.status).json(error).end()
    });

我立刻意识到这是愚蠢的,因为我正在回来并打破了我的循环。所以我去了这个:

尝试2

userDao.getBitbucketInfoForUser(token.id, cohortId)
    // Get Bitbucket information and make clones
    .then((teams) => {
        for(const team of teams) {
            console.log('Clone repo ' + sourceRepo + ' for Team-' + team.teamNumber);
            makeFork(gitInfo, sourceRepo, team)
                .then((result) => Promise.resolve(result));
        }
    })
    .then((result) => {
        const team = result.team;
        console.log('Wait for Team ' + team + ' repo');
    })
    .catch((error) => {
        console.log(error);
        response.status(error.status).json(error).end()
    });

这一次,它完成了makeFork中的所有通话,但只运行了then一次。接下来我尝试了这个:

尝试3

userDao.getBitbucketInfoForUser(token.id, cohortId)
    // Get Bitbucket information and make clones
    .then((teams) => {
        for(const team of teams) {
            console.log('Clone repo ' + sourceRepo + ' for Team-' + team.teamNumber);
            new Promise((resolve, reject) => resolve(makeFork(gitInfo, sourceRepo, team)));
        }
    })
    .then((result) => {
        const team = result.team;
        console.log('Wait for Team ' + result + ' repo');
    })
    .catch((error) => {
        console.log(error);
        response.status(error.status).json(error).end()
    });

这导致与尝试2完全相同的行为。有没有办法做我想做的事?

2 个答案:

答案 0 :(得分:1)

Promise.all非常适合您的使用案例。在继续链之前,它将等待您的所有makeFork承诺解决。一旦其中一个承诺失败并将错误正确地传播到catch,它也会失败。

由于您在评论中说您“想要对每个HTTP呼叫采取行动”,这可能意味着两件事之一。你想要:

  1. 首先获取HTTP请求的所有结果,然后以某种方式处理每个结果,然后继续沿着promise链。
  2. 处理结果时处理每个结果,然后在处理完所有结果后继续执行promise链。
  3. 第一个选项进一步分支,具体取决于结果处理是:

    • 异步(返回承诺):您需要使用其他Promise.all来处理makeFork的所有结果。
    • 同步(不返回承诺):您只需循环解析初始Promise.all后获得的结果并在那里进行处理。

    以下是代码如何查找所有案例:

    1。 首先解决所有请求,然后处理所有结果,然后继续沿着链

    userDao.getBitbucketInfoForUser(token.id, cohortId)
      .then(teams => Promise.all(
        teams.map(team =>
          makeFork(gitInfo, sourceRepo, team)
        )
      ))
    
      // the next `then` will get called once all makeFork requests are successfully resolved
    
      // use this if you have async processing of team results
      .then(arrayOfResultsForEachMakeForkRequest => Promise.all(
        arrayOfResultsForEachMakeForkRequest.map(processTeamResult)
      ))
    
      // or use this (without Promise.all) if you have sync processing of team results
      .then(arrayOfResultsForEachMakeForkRequest => 
        arrayOfResultsForEachMakeForkRequest.map(processTeamResult)
      )
    
      // either way, now you have your processed results
      // this part of the chain will be reached after every result is obtained and processed
      .then(processedResults => {
        // ...
      })
      .catch(reason => {
        // this will get called if any of the promises in any part of the chain fails
      })
    

    2. 处理每个结果,然后在处理完所有结果后继续进行链接

    userDao.getBitbucketInfoForUser(token.id, cohortId)
      .then(teams => Promise.all(
        teams.map(team =>
          makeFork(gitInfo, sourceRepo, team)
            .then(processTeamResult) // <-- the code will behave the same no matter if `processTeamResult` returns a promise that will resolve to a value or the value itself
        )
      ))
    
      // this part of the chain will be reached after every result is obtained and processed
      .then(processedResults => {
        // ...
      })
      .catch(reason => {
        // this will get called if any of the promises in any part of the chain fails
      })
    

    您可以使用代码中的相同功能作为processTeamResult的测试:

    const processTeamResult = (result) => {
      console.log('Wait for Team ' + result.team + ' repo');
      return result;
    }
    

    作为旁注,你最近的两次尝试都是完全相同的,这是因为他们都冗余地将另一个承诺附加到makeFork,除了之前和之后的承诺。在任何一种情况下,整个链都不会受到影响,因为您没有从then回调中返回承诺。

答案 1 :(得分:1)

你很亲密。正如其他用户所指出的Promise.all正是您想要的,即使您需要单独对每个元素采取行动。

userDao.getBitbucketInfoForUser(token.id, cohortId)
    // Get Bitbucket information and make clones
    .then((teams) => {
        // Act on each element individually.
        const teamPromises = teams.map((team) => {
            return makeFork(gitInfo, sourceRepo, team).then((result) => {
                const team = result.team;
                console.log('Wait for Team ' + team + ' repo');
            });
        });
        // Then resolve everything.
        return Promise.all(teamPromises);
    })
    .catch((error) => {
        console.log(error);
        response.status(error.status).json(error).end()
    });