【问题标题】:Using async/await to get data from a callback and return a value only after a promise is resolved使用 async/await 从回调中获取数据并仅在 promise 解决后返回值
【发布时间】:2017-12-20 02:42:38
【问题描述】:

我正在尝试使用 async/await,但我认为我严重误解了某些内容。

基本上,我正在尝试使用 google maps api 计算一系列位置与一个指定位置之间的距离。

这是我正在尝试做的一个粗略示例:https://jsfiddle.net/qu5y69rj/1/

您可以看到,该函数的结果是 undefined 3 次,而不是我所期望的,在我设计的示例中,每次调用都会是 {distance: "ZERO_RESULTS"}。

getDistance = async (start, end) => {
  const origin = new google.maps.LatLng(start[0], start[1]);
  const final = new google.maps.LatLng(end[0], end[1]);
  const service = new google.maps.DistanceMatrixService();
  let result; //need to return this value!
  await service.getDistanceMatrix(
    {
        origins: [origin],
      destinations: [final],
      travelMode: 'DRIVING'
    }, (response, status) => {
      if(status === 'OK') result = {distance: response.rows[0].elements[0].status}
    }
  )
  return result;
}

为什么在 promise 解决之前返回结果?只有在解决该承诺后,我才能返回 result 的值?我的理解是,通过告诉 javascript 等待,我是说在这个承诺得到解决之前不要继续前进。这是不正确的吗?我很困惑,这让我把头发拉了出来。任何帮助表示赞赏。

【问题讨论】:

  • async/await 只是包装承诺。我在这段代码中看不到任何承诺。 service.getDistanceMatrix 是您的代码吗?你能让它返回一个承诺而不是回调吗?
  • 不,它是谷歌地图 api 的一部分,所以它就是这样
  • 你不能await一个回调风格的异步函数。你应该先学习how to use promises,然后再尝试解决async / await。

标签: javascript asynchronous async-await


【解决方案1】:

service.getDistanceMatrix 接受回调,这意味着 ti 很可能不会返回承诺。

但是,异步函数需要 Promise。

作为修复,您可以将 getDistanceMatrix 包装在一个承诺中(或使用另一种返回承诺的方法):

const getDistanceMatrix = (service, data) => new Promise((resolve, reject) => {
  service.getDistanceMatrix(data, (response, status) => {
    if(status === 'OK') {
      resolve(response)
    } else {
      reject(response);
    }
  })
});

getDistance = async (start, end) => {
  const origin = new google.maps.LatLng(start[0], start[1]);
  const final = new google.maps.LatLng(end[0], end[1]);
  const service = new google.maps.DistanceMatrixService();
  const result = await getDistanceMatrix(
    service,
    {
      origins: [origin],
      destinations: [final],
      travelMode: 'DRIVING'
    }
  )
  return {
    distance: result.rows[0].elements[0].status
  };
};

【讨论】:

  • 太棒了,这就像一个魅力!所以我很清楚这一点,我都可以在我声明为async的函数中调用await?并调用await 会“暂停”代码,直到承诺被解决/拒绝?
  • 谢谢!巧妙的实现
【解决方案2】:

使用 JavaScript 进行异步操作的三种方法:

  1. 回调:函数接受回调作为其最终参数。它不返回任何内容 (undefined),并且当异步操作完成时,将调用回调。
  2. Promises:函数返回一个 Promise,它在完成时解析为异步操作的结果。
  3. Async/Await:函数返回一个promise,并且可以使用async 关键字在其定义中获取异步操作的值。使用 return 关键字返回的任何内容都将包装在一个 Promise 中。

由于getDistanceMatrix 接受回调,它什么也不返回。代码中使用的await 关键字不需要等待;它立即获得getDistanceMatrix 返回的undefined 值。当操作完成并调用回调时,getDistance早已执行完毕并返回。

您需要包装 getDistanceMatrix 使其返回一个承诺,让 getAllDistance() 也返回一个承诺,并在您的 console.log() 语句中等待该承诺:

const coords = [
  ['-36.22967', '-125.80271'],
  ['54.06395', '54.06395'],
  ['-5.00263', '-137.92806']
];

function getDistance (start, end) {
  const origin = new google.maps.LatLng(start[0], start[1]);
  const final = new google.maps.LatLng(end[0], end[1]);
  const service = new google.maps.DistanceMatrixService();

  return new Promise((resolve, reject) => {
    service.getDistanceMatrix(
    {
        origins: [origin],
      destinations: [final],
      travelMode: 'DRIVING'
    }, (response, status) => {
      if(status === 'OK') {
        resolve({ distance: response.rows[0].elements[0].status });
      } else {
        reject(new Error('Not OK'));
      }
    }
  );
  });
}

function getAllDistance (starts, end) {
  const promisedDistances = starts.map((start) => getDistance(start, end));
  // Promise.all turns an array of promises into a promise
  // that resolves to an array.
  return Promise.all(promisedDistances);
}

getAllDistance(coords, ['-30.23978', '-161.31203'])
  .then(result => { console.log(result); });

【讨论】:

    猜你喜欢
    • 2022-08-22
    • 2020-07-18
    • 2021-12-28
    • 2020-11-19
    • 2020-03-12
    • 2017-09-11
    • 2021-03-15
    • 1970-01-01
    相关资源
    最近更新 更多