【问题标题】:How to force callback method to wait for Google Markers creation如何强制回调方法等待 Google 标记创建
【发布时间】:2021-05-07 20:53:24
【问题描述】:

我正在使用 Google 地图库制作应用程序。我的问题是创建标记时出现无法解释的延迟,或者我有一个我看不到的异步问题。

说明: 该代码沿起点和终点之间的路线获取充电站位置,为获取返回的每个站创建 Google 标记(以 Json 格式)并将它们推送到数组中。稍后它应该使用这些标记(不包括在此处)来计算中途停留的路线。

问题是它在完成创建标记之前启动计算方法。

为了协调结果,我不会一次获取所有结果。相反,我做了一个循环,执行以下操作:

  1. 创建路线并从中提取编码折线(用于 URL)
  2. 获取结果
  3. 创建标记,在地图上设置它们并将它们推送到数组上
  4. 登录控制台作业完成('EV 标记创建完成')

然后它启动路由计算过程(这里替换为调用的alert 'calculateAndDisplayRoute 方法)

但实际上循环结束并登录控制台,但未创建最后一个标记,警报已启动,只有在您看到标记出现在地图上之后。

你可以试试下面的代码 sn -p :https://codepen.io/reivilo85k/pen/wvowpab

这是有问题的代码(我不得不在 codepen 中添加更多代码才能使其正常工作):

chargingPointsMarkers = [];
markerArray = [];

async callbackHandler(startEndPointsArray, calculateAndDisplayRoute): Promise<void> {
    await this.setChargingStationsMarkers();
    calculateAndDisplayRoute();
  }

function calculateAndDisplayRoute() {
      alert('calculateAndDisplayRoute method called')
    }

  async function setChargingStationsMarkers() {
const polylineMarkersArray = await createMarkersArray();
console.log('Polyline Markers created', polylineMarkersArray);

    const baseUrl = 'URL REMOVED';

    for (let j = 0; j < polylineMarkersArray.length - 1; j++) {
      const origin = polylineMarkersArray[j].getPosition();
      const destination = polylineMarkersArray[j + 1].getPosition();
      
      const route = await createRoute(origin, destination);
      const encodedPolyline = route.overview_polyline;
      const queryUrl = baseUrl + '&polyline='+ encodedPolyline + '&distance=50';

      await fetch(queryUrl)
        .then((response) => response.json())
        .then( async (data) => await createChargerPointMarkers(data))
        .then (() => {
                   const k = j + 1;
          const l = polylineMarkersArray.length - 1;
          if (j === polylineMarkersArray.length - 2) {
            console.log('loop ' + k + ' of ' + l);
            console.log('EV markers creation finished');
          }else{
            console.log('loop ' + k + ' of ' + l);
          }
        });
    }
}

async createChargerPointMarkers(jsonChargingPoints): Promise<void> {
    // Convert the Json response elements to Google Markers, places them on the Map and pushes them to an array.
    for (const item of jsonChargingPoints) {
      const LatLng = new google.maps.LatLng(parseFloat(item.AddressInfo.Latitude), parseFloat(item.AddressInfo.Longitude));
      const marker = await new google.maps.Marker({
        position: LatLng,
        map: this.map,
        draggable: false,
      });
      this.markerArray.push(marker);
      this.chargingPointsMarkers.push(marker);
    }
  }

  async createRoute(point1, point2): Promise<google.maps.DirectionsRoute> {
    // Returns a Google DirectionsRoute object
    const directionsService = new google.maps.DirectionsService();
    const request = {
      origin: point1,
      destination: point2,
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC
    };
    return new Promise(resolve => directionsService.route(request,
      (result, status) => {
        if (status === 'OK') {
          resolve(result.routes[0]);
        } else {
          window.alert('Directions request failed due to ' + status);
        }
      })
    );
  }

【问题讨论】:

  • 我认为您的代码没有问题。我相信问题在于使用 alert() 会阻止 UI 渲染,直到您单击确定。如果我在创建每个标记后添加一个console.log('marker added') 并用另一个控制台日志替换警报并执行您的代码,在最后一个循环中,我得到以下序列: (84) marker added > loop 6 of 6 > EV 标记创建完成 > 调用 calculateAndDisplayRoute 方法,因此您可以看到在调用 calculateAndDisplayRoute 之前创建了 84 个标记。只有alert() 在您的浏览器完成渲染之前触发。
  • @MrUpsidown 感谢您的评论并花时间在我的代码上。这非常有用。
  • 既然答案已经得到解答,我将删除 CodePen 中的 fetch URL

标签: javascript typescript asynchronous promise alert


【解决方案1】:

正如我在评论中提到的,您的代码按预期工作,问题来自使用 alert(),它在被触发时会阻止您的浏览器执行任何进一步的代码 - 更重要的是 - 进一步的 UI 渲染。

这很容易用几乎任何对 DOM 做某事的代码来重现。

const el = document.createElement("div");
const text = document.createTextNode("Hello world");

el.appendChild(text);
document.body.appendChild(el);

console.log('done');
alert('done');

警报被触发节点被添加到 DOM 但浏览器渲染它之前(至少在我的浏览器中)。

将代码中的 alert() 替换为 console.log() 并在创建每个 google.maps.Marker() 的位置添加另一个 console.log('marker added') 表明事件的顺序符合您的预期:

  1. (84) marker added
  2. loop 6 of 6
  3. EV markers creation finished
  4. calculateAndDisplayRoute method called

alert() 在浏览器完成渲染标记之前被触发。

您应该避免将alert() 用于调试目的,或者小心使用它,因为它可能会产生误导。

【讨论】:

  • 我故意使用 alert() 方法在这个确切时刻冻结程序,因为这是我的真实代码的行为方式(因为它会引发错误),所以这是故意的。例如,当启动此警报时,它还有助于查看获取已完成。但是,您假设我认为由于渲染延迟而未创建变量是正确的。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 2013-02-14
  • 2018-12-14
  • 1970-01-01
相关资源
最近更新 更多