简体   繁体   English

使用async / await从回调中获取数据并仅在解决承诺后返回值

[英]Using async/await to get data from a callback and return a value only after a promise is resolved

I'm trying to use async/await but I think I'm misunderstanding something critically. 我正在尝试使用async / await,但我认为我对某些事情有误解。

As basically as possible, I am trying to calculate the distance between a list of locations and one designated location using google maps api. 基本上,我正在尝试使用Google Maps API计算位置列表和一个指定位置之间的距离。

Here is a rough example of what I'm trying to do: https://jsfiddle.net/qu5y69rj/1/ 这是我要执行的操作的粗略示例: https : //jsfiddle.net/qu5y69rj/1/

You can see that the result of that function is undefined 3 times instead of what I would expect which would be {distance: "ZERO_RESULTS"} for each call in the case of my contrived example. 您可以看到该函数的结果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;
}

Why is result being returned before the promise is resolved? 为什么在解决诺言之前返回结果? How can I return the value of result only after that promise is resolved? 只有兑现了承诺,我如何才能返回result的值? It is my understanding that by telling javascript to await, I'm saying don't move forward until this promise has resolved. 据我了解,通过告诉javascript等待,我是说直到这个诺言得以解决之前,不要前进。 Is that incorrect? 那不对吗? I'm pretty confused and this has me pulling my hair out. 我很困惑,这让我拔头发。 Any help is appreciated. 任何帮助表示赞赏。

The service.getDistanceMatrix accepts a callback which means ti most likely doesn't return a promise. service.getDistanceMatrix接受回调,这意味着ti最有可能不返回承诺。

However, async functions expect promises. 但是,异步功能会带来希望。

As a fix, you can wrap getDistanceMatrix it in a promise (or use another method that does return a promise): 作为解决方法,您可以将getDistanceMatrix包裹在一个getDistanceMatrix中(或使用另一个返回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
  };
};

There are three ways to do async operations with JavaScript: 使用JavaScript进行异步操作的方法有以下三种:

  1. Callbacks : A function accepts a callback as its final argument. 回调 :函数接受回调作为其最终参数。 It returns nothing ( undefined ), and when the async operation completes, the callback is called. 它不返回任何内容( undefined ),并且在异步操作完成时,将调用回调。
  2. Promises : A function returns a promise, which resolves to the result of the async operation when it completes. Promises :函数返回一个Promise,该函数在完成时将解析为异步操作的结果。
  3. Async/Await : A function returns a promise, and can use the async keyword to get the values of async operations inside its definition. Async / Await :函数返回一个Promise,并且可以使用async关键字在其定义内获取异步操作的值。 Whatever is returned using the return keyword will be wrapped in a promise. 使用return关键字返回的任何内容都将包装在promise中。

Since getDistanceMatrix accepts a callback, it returns nothing. 由于getDistanceMatrix接受回调,因此不返回任何内容。 The await keyword as used in the code doesn't need to wait; 代码中使用的await关键字不需要等待; it immediately gets the undefined value returned by getDistanceMatrix . 它立即获得getDistanceMatrix返回的undefined值。 When the operation completes and the callback is called, the getDistance has long finished executing and returned. 当操作完成并调用回调时, getDistance早已完成执行并返回。

You need to wrap getDistanceMatrix so it returns a promise, make getAllDistance() return a promise as well, and await that promise in your console.log() statement: 您需要包装getDistanceMatrix以便它返回一个promise,使getAllDistance()返回一个promise,并在console.log()语句中等待该promise:

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); });

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

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