【问题标题】:Returning value from multiple promises within Meteor.method从 Meteor.method 中的多个承诺返回值
【发布时间】:2018-08-18 22:30:40
【问题描述】:

在研究了 Futures、Promises、wrapAsync 之后,我仍然不知道如何解决这个问题

我有这个方法,它获取一组图像,将其发送到 Google Cloud Vision 进行徽标检测,然后将所有检测到的带有徽标的图像推送到一个数组中,我尝试在我的方法中返回。

Meteor.methods({
  getLogos(images){
    var logosArray = [];
    images.forEach((image, index) => {
        client
        .logoDetection(image)
        .then(results => {
            const logos = results[0].logoAnnotations;
            if(logos != ''){
                logos.forEach(logo => logosArray.push(logo.description));
            }
        })
    });
    return logosArray;      
  },
});

但是,当从客户端调用该方法时:

Meteor.call('getLogos', images, function(error, response) {
  console.log(response);
});

总是返回空数组,这是可以理解的,因为在 Google 处理完所有数组并返回结果之前,该方法返回了 logosArray

遇到这种情况怎么办?

【问题讨论】:

  • 你至少应该收到你的空数组,而不是undefined
  • 是的,返回一个空数组,我的错。我已经编辑了问题。

标签: javascript asynchronous meteor google-cloud-vision


【解决方案1】:
  1. 使用 Meteor 方法,您实际上可以简单地“返回一个 Promise”,而 Server 方法将在内部等待 Promise 解决,然后再将结果发送给客户端:
Meteor.methods({
  getLogos(images) {
    return client
      .logoDetection(images[0]) // Example with only 1 external async call
      .then(results => {
        const logos = results[0].logoAnnotations;
        if (logos != '') {
          return logos.map(logo => logo.description);
        }
      }); // `then` returns a Promise that resolves with the return value
          // of its success callback
  }
});
  1. 您还可以将 Promise 语法转换为 async / await。通过这样做,您不再显式返回 Promise(但实际上仍然如此),而是“等待” Promise 在您的方法代码中解析。
Meteor.methods({
  async getLogos(images) {
    const results = await client.logoDetection(images[0]);
    const logos = results[0].logoAnnotations;
    if (logos != '') {
      return logos.map(logo => logo.description);
    }
  }
});
  1. 一旦您理解了这个概念,您就可以逐步处理多个异步操作,并在所有操作完成后返回结果。为此,您可以简单地使用Promise.all
Meteor.methods({
  getLogos(images) {
    var promises = [];
    images.forEach(image => {
      // Accumulate the Promises in an array.
      promises.push(client.logoDetection(image).then(results => {
        const logos = results[0].logoAnnotations;
        return (logos != '') ? logos.map(logo => logo.description) : [];
      }));
    });
    return Promise.all(promises)
      // If you want to merge all the resulting arrays...
      .then(resultPerImage => resultPerImage.reduce((accumulator, imageLogosDescriptions) => {
        return accumulator.concat(imageLogosDescriptions);
      }, [])); // Initial accumulator value.
  }
});

async/await:

Meteor.methods({
  async getLogos(images) {
    var promises = [];
    images.forEach(image => {
      // DO NOT await here for each individual Promise, or you will chain
      // your execution instead of executing them in parallel
      promises.push(client.logoDetection(image).then(results => {
        const logos = results[0].logoAnnotations;
        return (logos != '') ? logos.map(logo => logo.description) : [];
      }));
    });
    // Now we can await for the Promise.all.
    const resultPerImage = await Promise.all(promises);
    return resultPerImage.reduce((accumulator, imageLogosDescriptions) => {
      return accumulator.concat(imageLogosDescriptions);
    }, []);
  }
});

【讨论】:

  • 这个解决方案非常完美,非常感谢!除了语法上的差异,async/await 和 Promise 解决方案之间是否存在差异?
  • 正如你在上面看到的,async/await 隐藏了底层的 Promise,它在简单的情况下简化了代码,但使得并行化任务变得不可能。因此需要借助 Promise 传递给 Promise.all。但技术上没有其他区别,async/await 本质上是糖。
猜你喜欢
  • 1970-01-01
  • 2013-12-04
  • 2018-03-10
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 2015-06-05
  • 2019-01-23
相关资源
最近更新 更多