简体   繁体   English

如何在Promise.all()中使用async-await?

[英]How to use async-await with Promise.all()?

At the moment I am using this code below to get the results of several Promises using async await: 目前,我正在使用以下代码使用async await获取多个Promises的结果:

let matchday = await createMatchday(2018, 21, [/*9 matches of matchday*/]);
//Further calculations

async function createMatchday(seasonNr, matchdayNr, matches) {
  let md = new Matchday(seasonNr, matchdayNr, matches);
  await md.getStandings(seasonNr, matchdayNr);
  return md;
}

class Matchday {
  constructor(seasonNr, matchdayNr, matches) {
    this.seasonNr = seasonNr;
    this.matchdayNr = matchdayNr;
    this.matches = matches;
  }

  async getStandings(seasonNr, matchdayNr) {
    let promiseArr = [];
    promiseArr.push(makeHttpRequestTo(`http://externService.com/standings?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`);
    promiseArr.push(makeHttpRequestTo(`http://externService.com/homestandings?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`));
    promiseArr.push(makeHttpRequestTo(`http://externService.com/awaystandings?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`));
    promiseArr.push(makeHttpRequestTo(`http://externService.com/formstandings?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`));

    let resulArr = await Promise.all(promiseArr);
    this.standings = resultArr[0];
    this.homeStandings = resultArr[1];
    this.awayStandings = resultArr[2];
    this.formStandings = resultArr[3];
  }
}

function makeHttpRequest(url) {
  return new Promise((resolve, reject) => {
    //AJAX httpRequest to url
    resolve(httpRequest.responseText);
  }
}

Is this actually the best way to read the values of several promises where the promises don't need to wait for each other to end but rather work at the same time by using Promise.all() or is there a better way to make eg several httpRequests at the same time because this seems quite repetetive? 这实际上是读取多个promise值的最佳方式,其中promise.all()不需要相互等待对方就可以完成承诺,还是有更好的方法来生成例如同时出现几个httpRequest,因为这看起来很重复吗?

Your URLs all follow the same sort of pattern, so you can greatly reduce your code by map ping an array of ['', 'home', 'away', 'form'] to the URLs. 您的URL都遵循相同的模式,因此您可以通过map ['', 'home', 'away', 'form']数组map到URL来大大减少代码。 Then, map those URLs to Promises through makeHttpRequestTo , and then you can destructure the awaited results into the this. 然后,通过makeHttpRequestTo map这些URL map到Promises,然后可以将等待的结果分解为this. properties: 特性:

async getStandings(seasonNr, matchdayNr) {
  const urls = ['', 'home', 'away', 'form']
    .map(str => `http://externService.com/${str}standings?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`);
  const promiseArr = urls.map(makeHttpRequestTo);
  [
    this.standings,
    this.homeStandings,
    this.awayStandings,
    this.formStandings
  ] = await Promise.all(promiseArr);
}

To populate each property individually rather than waiting for all responses to come back: 要单独填充每个属性,而不是等待所有响应返回:

async getStandings(seasonNr, matchdayNr) {
  ['', 'home', 'away', 'form']
    .forEach((str) => {
      const url = `http://externService.com/${str}standings?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`;
      makeHttpRequestTo(url)
        .then((resp) => {
          this[str + 'Standings'] = resp;
        });
    });
}

To answer, No you shouldn't block other XHR or any I/O request which are not dependent on each other. 要回答,不,您不应阻止彼此不依赖的其他XHR或任何I / O请求。 I would have written your function like this; 我会这样写你的函数的;

 const getFavourites = async () => { try { const result = await Promise.resolve("Pizza"); console.log("Favourite food: " + result); } catch (error) { console.log('error getting food'); } try { const result = await Promise.resolve("Monkey"); console.log("Favourite animal: " + result); } catch (error) { console.log('error getting animal'); } try { const result = await Promise.resolve("Green"); console.log("Favourite color: " + result); } catch (error) { console.log('error getting color'); } try { const result = await Promise.resolve("Water"); console.log("Favourite liquid: " + result); } catch (error) { console.log('error getting liquid'); } } getFavourites(); 

This way every async functions will be called at once, and no async action will block the other action. 这样,将立即调用每个异步函数,并且没有异步动作将阻止其他动作。

If you don't want to wait for all requests to complete before continuing the execution flow, you could make the properties of the class be promises: 如果您不希望在继续执行流程之前等待所有请求完成,则可以使该类的属性成为应许:

class Matchday {
  constructor(seasonNr, matchdayNr, matches) {
    this.seasonNr = seasonNr;
    this.matchdayNr = matchdayNr;
    this.matches = matches;
    ['standings', 'homeStandings', 'awayStandings', 'formStandings'].forEach(propertyName => {
      let url = `http://externService.com/${propertyName.toLowerCase()}`
        + `?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}`
      this[propertyName] = makeHttpRequestTo(url)
    });
  }
}

Test using the following snippet 使用以下代码段进行测试

 class Matchday { constructor(seasonNr, matchdayNr, matches) { this.seasonNr = seasonNr; this.matchdayNr = matchdayNr; this.matches = matches; ['standings', 'homeStandings', 'awayStandings', 'formStandings'].forEach(propertyName => { let url = `http://externService.com/${propertyName.toLowerCase()}` + `?seasonNr=${seasonNr}&matchdayNr=${matchdayNr}` this[propertyName] = makeHttpRequestTo(url) }); } } /************************************** * Test harness **************************************/ function makeHttpRequestTo(url) { // Fake an AJAX httpRequest to url const requested_resource = url.match('^.*\\/\\/.*\\/([^?]*)')[1]; const fake_response_data = 'data for ' + url.match('^.*\\/\\/.*\\/(.*)$')[1]; let delay = 0; let response = ''; switch (requested_resource) { // To make it interesting, let's give the 'standings' resource // a much faster response time case 'standings': delay = 250; break; case 'homestandings': delay = 2000; break; case 'awaystandings': delay = 3000; break; case 'formstandings': delay = 4000; // <== Longest request is 4 seconds break; default: throw (util.format('Unexpected requested_resource: %s', requested_resource)); } return new Promise((resolve, reject) => { setTimeout(() => resolve(fake_response_data), delay); }); } async function testAccessingAllProperties() { const testId = "Test accessing all properties"; console.log('\\n%s', testId); console.time(testId) let md = new Matchday(2018, 21, []); console.log(await md.standings); console.log(await md.homeStandings); console.log(await md.awayStandings); console.log(await md.formStandings); console.timeEnd(testId) } async function testAccessingOnlyOneProperty() { const testId = `Test accessing only one property`; console.log('\\n%s', testId); console.time(testId) let md = new Matchday(2018, 21, []); console.log(await md.standings); console.timeEnd(testId) } async function all_tests() { await testAccessingAllProperties(); await testAccessingOnlyOneProperty(); } all_tests(); 

Conclusion 结论

The above snippet shows that the execution time is not penalized by properties that are not accessed. 上面的代码片段显示,执行时间不会因未访问的属性而受到影响。 And execution time of accessing all properties is no worse than using promise.all . 并且访问所有属性的执行时间并不比使用promise.all差。

You'd just need to remember to use await when accessing those properties. 您只需要记住在访问这些属性时使用await即可。

To create a Promise you need to call new Promise((resolve, reject) => { return "Pizza"; }) 要创建一个Promise,您需要调用新的Promise((resolve,reject)=> {return“ Pizza”;})

You're doing it the right way 你做对了

If you want you can shorten the code by using an array (and its functions like map , etc...), but it won't improve its performance 如果您愿意,可以使用数组(及其功能,例如map等)来缩短代码,但不会提高其性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM