Using async / await to retrieve data from a callback and return a value only after resolving a promise

I am trying to use async / await, but I think I am misunderstanding something critically.

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

Here is a rough example of what I'm trying to do: https://jsfiddle.net/qu5y69rj/1/

You can see that the result of this function is undefined 3 times instead of what I would expect if there were {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 the result returned before the promise is resolved? How to return result value only after this promise will be resolved? As far as I understand, saying that javascript is waiting, I say, do not move forward until this promise is resolved. It is not right? I'm pretty confused, and it made me pull my hair out. Any help is appreciated.

+5
source share
2 answers

service.getDistanceMatrix takes a callback, which means that ti most likely will not return a promise.

However, asynchronous functions expect promises.

As a fix, you can wrap getDistanceMatrix in a promise (or use another method that returns 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
source

There are three ways to perform asynchronous operations with JavaScript:

  • Callbacks . The function takes the answer as the last argument. It returns nothing ( undefined ), and when the async operation completes, a callback is called.
  • Promises : the function returns a promise that resolves the result of the async operation upon completion.
  • Async / Await : The function returns a promise and can use the async keyword to get the values โ€‹โ€‹of asynchronous operations inside its definition. Anything returned with the return keyword will be completed in promise.

Since getDistanceMatrix accepts the callback, it returns nothing. The await keyword used in the code does not have to wait; it immediately gets the undefined value returned by getDistanceMatrix . When the operation completes and the callback is called, getDistance has a long finished result and returns.

You need to wrap getDistanceMatrix so that it makes a promise, also make getAllDistance() return the promise and expect this promise in the 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); }); 
+3
source

Source: https://habr.com/ru/post/1274199/


All Articles