0

私は Java 開発者の学生ですが、Javascript で非同期関数を適切に記述する方法を理解するのに問題があります。多くのチュートリアルを読みましたが、常に適切な非同期メソッドを実装する良い方法が見つかりません。

私は Google Maps API を使用してアプリを作成しており、結果オブジェクトから overview_polyline 値を取得するために、directionService API を使用したいメソッドで作成しています。メソッドは本来あるべきことを行いますが、データを受け取る前に未定義のオブジェクトを返します。

メソッドは次のようになります。

「開始」変数と「終了」変数はどちらも Google マーカーです

  async createPolyline(startEndPointsArray){
    //Creates a polyline
    const directionsService = new google.maps.DirectionsService();
    const request = {
      origin: this.start.getPosition(),
      destination: this.end.getPosition(),
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC
    };

   const getData = await directionsService.route(request,
      function (result, status) {
        if (status === "OK") {
          console.log(result.routes[0].overview_polyline)
          return result.routes[0].overview_polyline;
        } else {
          window.alert("Directions request failed due to " + status);
        }
      });
    getData.then(data => {return data})
  }

getData は null のままなので、問題は関数内にあると思います

そして、参考までに、同期でもあるこのメソッドから呼び出されます

 async setChargingStationsMarkers(startEndPointsArray) {
   
    const polyline = await this.createPolyline(startEndPointsArray);
    console.log(polyline);

[some additional code fetching a json response from an external website...]

コード スニペット (コメントのフィドルから)

let map;
let mapCenter = { lat: 59.428, lng: 24.76};
let start;
let end;
let chargingPointsMarkers = [];
let markerArray = [];
let stopoverMarkers = []
let vehicle1 = {capacity: 33, status: 33, consumption: 6.6666} //1KW = 6.6666 Km; Capacity in KM = status*consumption;

function initMap(listener) {
    //Create the map, the DirectionsService, the DirectionsRenderer and an eventListener for the GO button
    //If I chose to implement a detailed steps display it would also be created here
    const directionsService = new google.maps.DirectionsService();

    const mapOptions = {
        center: mapCenter,
        zoom: 7,
    }
    map = new google.maps.Map(document.getElementById("map"), mapOptions);

    const directionsRenderer = new google.maps.DirectionsRenderer({map: map});

    //const stepDisplay = new google.maps.InfoWindow();

    const geocoder = new google.maps.Geocoder();
    document.getElementById("submit").addEventListener("click", () => {
        launcher(geocoder, directionsRenderer, directionsService);
    });
}


async function launcher(geocoder, directionsRenderer, directionsService){
    //the method is used to be launched by the eventListener
    //it sets up the start and end points, fetches the EV markers and launches the route calculation process though a callback function
    resetMarkers();
    const startEndPointsArray =  await setupRoutingProcess(geocoder);
    await callbackHandler(startEndPointsArray,directionsRenderer,
        directionsService, calculateAndDisplayRoute);
}

function setMapOnAll(map){
    // Sets the map on all markers in the array.
    for (let i = 0; i < markerArray.length; i++) {
        markerArray[i].setMap(map);
    }
}

function clearMarkers() {
    // Removes the markers from the map, but keeps them in the array.
    setMapOnAll(null);
}

function resetMarkers(){
    // Pushes all visible markers to a same array,
    // launches the different reset processes and
    // deletes all markers in the arrays by removing references to them.
    for (let i = 0; i < chargingPointsMarkers.length; i++) {
        markerArray.push(chargingPointsMarkers[i])
    }
    chargingPointsMarkers = [];

    for (let j = 0; j < stopoverMarkers.length; j++) {
        markerArray.push(stopoverMarkers[j])
    }
    stopoverMarkers = [];

    clearMarkers();

    markerArray = []
}

async function setupRoutingProcess(geocoder){
    //launches the setGeocodeAddress method for both start and end points and stores them in an array
    start = await setGeocodeAddress(geocoder, map, "start");
    end = await setGeocodeAddress(geocoder, map, "end");
    let startEndPointsArray = [start];
    startEndPointsArray.push(end);
    return startEndPointsArray;

}

async function setGeocodeAddress(geocoder, resultsMap, elementId) {
    //Retrieve the addresses (strings) from the html text boxes and uses Geocoder to Google Markers objects.
    //it pushes those markers in an array later used to delete the markers on the map
    const address = document.getElementById(elementId).value;
    return new Promise(resolve => geocoder.geocode({address: address},
        (results, status) => {
            if (status === "OK") {
                resultsMap.setCenter(results[0].geometry.location);
                const marker = new google.maps.Marker({
                    map: resultsMap,
                    position: results[0].geometry.location,
                    title: elementId,
                });
                resolve(marker)
                markerArray.push(marker);
            } else {
                alert("Trip Route finder was not successful for the following reason: " + status);
            }
        }));
}

async function callbackHandler (startEndPointsArray,
                                directionsRenderer,
                                directionsService,
                                calculateAndDisplayRoute){

    let jsonChargingPoints = await setChargingStationsMarkers(startEndPointsArray, directionsRenderer,
        directionsService, calculateAndDisplayRoute);


    await createChargerPointMarkers(jsonChargingPoints)

    calculateAndDisplayRoute(
        directionsRenderer,
        directionsService,
        jsonChargingPoints
    );
}

async function setChargingStationsMarkers(startEndPointsArray, directionsRenderer,
                                          directionsService, calculateAndDisplayRoute) {
    //Creates an encoded polyline to be passed as an Url argument to limit the results
    //fetches the EV Charging Points as Json response
    const polyline = await createPolyline(startEndPointsArray);
    console.log(polyline);
    const baseUrl = 'https://api.openchargemap.io/v3/poi/?output=json&maxresults=200&includecomments=true';
    const queryUrl = baseUrl + '&polyline=' + polyline + '&distance=50';
    let data  = await fetch(queryUrl)
        .then((response) => response.json())
        .then((data) => {return data})
    return data;
}

  async function createPolyline(startEndPointsArray){
    //Creates a polyline
    const directionsService = new google.maps.DirectionsService();
    const request = {
      origin: start.getPosition(),
      destination: end.getPosition(),
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC
    };

   const getData = await directionsService.route(request,
      function (result, status) {
        if (status === "OK") {
          console.log(result.routes[0].overview_polyline)
          return result.routes[0].overview_polyline;
        } else {
          window.alert("Directions request failed due to " + status);
        }
      });
    console.log(getData)
    getData.then(data => {return data})
  }

function createChargerPointMarkers(jsonChargingPoints) {
    //Loop through the Json response and launch the PlaceMarkers function
    for (let x = 0; x < jsonChargingPoints.length; x++) {
        const LatLng = new google.maps.LatLng(parseFloat(jsonChargingPoints[x].AddressInfo.Latitude), parseFloat(jsonChargingPoints[x].AddressInfo.Longitude));
        placeMarker(LatLng);
    }
}

function placeMarker(location) {
    //Convert the Json response elements to Google Markers, places them on the Map and pushes them to an array.
    let marker = new google.maps.Marker({
        position: location,
        map,
        icon: {
            path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
            scale: 3,
        },
        draggable: false,
    });
    markerArray.push(marker)
    chargingPointsMarkers.push(marker)
}

async function calculateAndDisplayRoute(
    directionsRenderer,
    directionsService,
    jsonChargingPoints,
    stepDisplay,
    map) {

    if (!compareVehicleCapacityToDistance(vehicle1, start)) {
        setChargeCheckpoint(vehicle1)
    }

    directionsService.route(setRequest(),
        function (result, status) {
            if (status === "OK") {
                directionsRenderer.setDirections(result);
                // showSteps(result, markerArray, stepDisplay, map);
            } else {
                window.alert("Directions request failed due to " + status);
            }
        });
}

function setRequest(){
    //prepares the request sent to the Directions service
    let stopovers = [];
    for (let x = 0; x < stopoverMarkers.length; x++){
        let latLng = stopoverMarkers[x].getPosition();
        let waypoint = {
            location: latLng,
            stopover: true
        };
        stopovers.push(waypoint)
    }

    const request = {
        origin: start.getPosition(),
        destination: end.getPosition(),
        waypoints: stopovers,
        travelMode: google.maps.TravelMode.DRIVING,
        unitSystem: google.maps.UnitSystem.METRIC
    };
    return request;
}

function compareVehicleCapacityToDistance(vehicle, p1){
    //Checks if the distance to destination is greater than the vehicle capacity
    if (calculateDistance(p1, end) > (vehicle.status*vehicle.consumption)){
        return false
    }return true;
}

function setChargeCheckpoint(vehicle){
    //launches the function selecting the closest marker to destination
    //Setting a marker of the selected marker on the map (might be redundant)
    //Pushes it to markerArray for later deletion (might be redundant)
    //Pushes it to stopoverMarkers to be used by the Directions service to setup a route
    let waypoint = selectMarkerClosestToDestination(vehicle);
    const waypointLocation = waypoint.getPosition();
    const marker = new google.maps.Marker({
        position: waypointLocation,
        stopover: true,
        draggable: false,
        title: "EV charging stopover"
    });
    markerArray.push(marker)
    stopoverMarkers.push(marker)
}



function selectMarkerClosestToDestination(vehicle) {
    //Selecting the closest marker to destination as long as it is not out of the vehicle capacity range
    //CURRENTLY BUGGED
    let waypoints = chargingPointsMarkers;

    for (let x = waypoints.length -1; x >= 0; x--) {
        if(calculateDistance(waypoints[x], start) > (vehicle.status*vehicle.consumption)){
            waypoints.splice(x, 1)
        }
    }

    for (let x = waypoints.length - 1; x > 0; x--) {
        if (calculateDistance(waypoints[x], end) > (calculateDistance(waypoints[x-1], end))) {
            waypoints.splice(x, 1);
        } else {
            waypoints.splice(x - 1, 1);
        }
    }
    return waypoints[0];
}

function calculateDistance(p1, p2) {
    //Uses the Google geometry library to calculate distance between two Markers
    let a = p1.getPosition();
    let b = p2.getPosition();

    let distance = (google.maps.geometry.spherical.computeDistanceBetween(a, b) / 1000).toFixed(2);
    return distance;
}

function showSteps(directionResult, stepDisplay, map) {
    // For each step, place a marker, and add the text to the marker's infowindow.
    // Also attach the marker to an array so we can keep track of it and remove it
    // when calculating new routes.
    //NOT CURRENTLY IMPLEMENTED/USED
    const myRoute = directionResult.routes[0].legs[0];

    for (let i = 0; i < myRoute.steps.length; i++) {
        const marker = (markerArray[i] =
            markerArray[i] || new google.maps.Marker());
        marker.setMap(map);
        marker.setPosition(myRoute.steps[i].start_location);
        attachInstructionText(
            stepDisplay,
            marker,
            myRoute.steps[i].instructions,
            map
        );
    }
}

function attachInstructionText(stepDisplay, marker, text, map) {
    google.maps.event.addListener(marker, "click", () => {
        // Open an info window when the marker is clicked on, containing the text
        // of the step.
        //NOT CURRENTLY IMPLEMENTED/USED
        stepDisplay.setContent(text);
        stepDisplay.open(map, marker);
    });
}
/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
#map {
    height: 90%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#floating-panel {
    position: absolute;
    top: 10px;
    left: 25%;
    z-index: 5;
    background-color: #fff;
    padding: 5px;
    border: 1px solid #999;
    text-align: center;
    font-family: "Roboto", "sans-serif";
    line-height: 30px;
    padding-left: 10px;
}

#warnings-panel {
    width: 100%;
    height: 10%;
    text-align: center;
}
<!DOCTYPE html>
<html>
<head>
    <title>EV Trip Route Finder</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
            src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=&v=weekly"
            defer
    ></script>
</head>
<body>
<div id="floating-panel" >
    <b>Start: </b>
    <input id="start" type="text" value="Nantes">
    <b>End: </b>
    <input id="end" type="text" value="Paris">
    <input id="submit" type="button" value="GO" />
</div>
<div id="map"></div>
<div id="warnings-panel"></div>
</body>
</html>

4

1 に答える 1