【问题标题】:Spawning Multiple Promises产生多个 Promise
【发布时间】:2017-09-30 16:27:12
【问题描述】:

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

尝试 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 完全相同的行为。有没有办法做我想做的事?

【问题讨论】:

标签: javascript node.js promise es6-promise


【解决方案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()
    });

【讨论】:

    【解决方案2】:

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

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

    1. 首先获取 HTTP 请求的所有结果,然后以某种方式处理每个结果,然后继续沿着 Promise 链。
    2. 在解决每个结果时对其进行处理,然后在处理完所有结果后继续执行承诺链。

    第一个选项根据结果处理是否进一步分支:

    • 异步(返回一个承诺):您需要使用另一个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;
    }
    

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

    【讨论】:

      猜你喜欢
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      • 1970-01-01
      • 1970-01-01
      • 2016-03-01
      • 2020-06-26
      • 2018-01-07
      相关资源
      最近更新 更多