使用async / await从回调中获取数据,并仅在解析promise后返回值

时间:2017-12-19 18:10:36

标签: javascript asynchronous async-await

我正在尝试使用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;
}

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

2 个答案:

答案 0 :(得分:7)

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

但是,异步函数需要承诺。

作为修复,您可以将getDistanceMatrix包装在一个promise中(或者使用另一个返回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
  };
};

答案 1 :(得分:4)

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

  1. 回调:函数接受回调作为其最终参数。它不返回任何内容(undefined),当异步操作完成时,将调用回调函数。
  2. Promises :函数返回一个promise,它在完成时解析为异步操作的结果。
  3. Async / Await :函数返回一个promise,可以使用async关键字在其定义中获取异步操作的值。使用return关键字返回的内容将包含在一个承诺中。
  4. 由于getDistanceMatrix接受回调,因此不返回任何内容。代码中使用的await关键字不需要等待;它立即获得undefined返回的getDistanceMatrix值。当操作完成并且调用回调时,getDistance已经完成执行并返回。

    您需要包装getDistanceMatrix以便它返回一个promise,make 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); });