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

你离开我真会死。 提交于 2020-02-01 03:27:07

问题


I'm trying to use async/await but I think I'm misunderstanding something critically.

As basically as possible, I am trying to calculate the distance between a list of locations and one designated location using google maps api.

Here is a rough example of what I'm trying to do: 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.

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? It is my understanding that by telling javascript to await, I'm saying don't move forward until this promise has resolved. Is that incorrect? I'm pretty confused and this has me pulling my hair out. Any help is appreciated.


回答1:


The service.getDistanceMatrix accepts a callback which means ti most likely doesn't return a promise.

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):

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



回答2:


There are three ways to do async operations with 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.
  2. Promises: A function returns a promise, which resolves to the result of the async operation when it completes.
  3. Async/Await: A function returns a promise, and can use the async keyword to get the values of async operations inside its definition. Whatever is returned using the return keyword will be wrapped in a promise.

Since getDistanceMatrix accepts a callback, it returns nothing. The await keyword as used in the code doesn't need to wait; it immediately gets the undefined value returned by getDistanceMatrix. When the operation completes and the callback is called, the getDistance has long finished executing and returned.

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:

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


来源:https://stackoverflow.com/questions/47892884/using-async-await-to-get-data-from-a-callback-and-return-a-value-only-after-a-pr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!