Запустить функцию Async как Sync

LorD спросил: 28 марта 2018 в 04:18 в: javascript

Я новичок в программировании javascript, и я пытаюсь понять процесс async. Я начал проект, и я хотел бы знать, как выполнить код ниже как синхронизацию. Я видел много учебников, но большинство из них настолько поверхностны ...

Код прост, его вызов Google Maps api, который передает адрес и возвращает широту и долготу. После этого он должен вызвать передачу сервера lat lng через url и вернуть все местоположения рядом с указанным местоположением.

Клиент:

$scope.findLocations = function () {    var dist = 0.1;    //execute this
    getLatLong();    //before this
    $http.get('/api/locations/findByLocation/'+$scope.form.lng+'/'+$scope.form.lat+'/'+dist)
    .success(function(data) {
        $scope.locations = data;
        $scope.form = {};
        console.log("locations: ", data);
    })
    .error(function(data) {
        console.log('Error: ' + data);
    });};var getLatLong = function() {    var geo = new google.maps.Geocoder;    var address = $scope.form.adress;    console.log(address);    geo.geocode({'address':address},function(results, status){
        if (status == google.maps.GeocoderStatus.OK) {
            console.log("Status geocoder OK");
            $scope.form.lat = results[0].geometry.location.lat();
            $scope.form.lng = results[0].geometry.location.lng();            var latlng = new google.maps.LatLng($scope.form.lat,$scope.form.lng);            var mapProp = {
                    center:latlng,
                    zoom:18,
                    mapTypeId:google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
            };            var map=new google.maps.Map(document.getElementById("map"),mapProp);
            var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title:name
            });            } else {
            alert(status);
        }      });};

Сервер:

router.get('/api/locations/findByLocation/:lng/:lat/:dist', function(req, res){var coords = [];
coords[0] = req.params.lng;
coords[1] = req.params.lat;Location.find({
    loc: {
        $near: coords,
        $maxDistance: req.params.dist
    }
}).limit(30).exec(function(err, locations){    if(err){
        res.json(err);
        console.log(err);
    }    res.json(locations);
});});

4 ответа

Есть решение
Nishant Dixit ответил: 28 марта 2018 в 04:28

Используйте JS Promise для этого

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

$scope.findLocations = function() {    var dist = 0.1;    //execute this
    getLatLong().then(function(resolve) {
        //before this
        $http.get('/api/locations/findByLocation/' + $scope.form.lng + '/' + $scope.form.lat + '/' + dist)
            .success(function(data) {
                $scope.locations = data;
                $scope.form = {};
                console.log("locations: ", data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    }, function(error) {
        alert("You got some error!");
    });};var getLatLong = function() {    var geo = new google.maps.Geocoder;    var address = $scope.form.adress;    console.log(address);    return new Promise(function(resolve, reject) {        geo.geocode({
            'address': address
        }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Status geocoder OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);                var mapProp = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };                var map = new google.maps.Map(document.getElementById("map"), mapProp);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });                resolve(200);
            } else {
                reject(status);
            }        });
    });
};
Nishant Dixit ответил: 28 марта 2018 в 04:33
Я думаю, что это хорошо для избирателей, оставивших некоторые комментарии, чтобы я мог осознать свою ошибку. Спасибо.
Yanis-git ответил: 28 марта 2018 в 04:33
Ваша реализация хороша и точно соответствует реальной проблеме, также не понимаю почему. Только что закончите, чтобы написать мой образец через пару минут после того, как вы и у меня такой же подход, чтобы решить эту проблему.
dark_ruby ответил: 28 марта 2018 в 04:37
Не понизил, но я думаю, что вы устали, потому что обещания не заставляют ваш асинхронный код работать синхронно.
Nishant Dixit ответил: 28 марта 2018 в 04:45
@dark_ruby В Javascript нет ничего, что позволяло бы вам запускать асинхронный код синхронно, кроме async / await, но я не упомянул об этом выше, потому что в некоторых старых браузерах отсутствует поддержка, поэтому я привожу пример с Promise, который работает практически со всеми браузеры по сравнению с async / await.
dark_ruby ответил: 28 марта 2018 в 06:08
@NishantDixit да, я знаю. Вы спросили, почему downvote, я дал вам объяснение. На самом деле, даже async / await не делает ваш код синхронным, он только делает его синхронным.
Yanis-git ответил: 28 марта 2018 в 04:33

Вы должны проверить, как Promise работает в JavaScript. вот пример:

var getLastLong = function() {
    return $q(function(resolve, reject) {        var geo = new google.maps.Geocoder;        var address = $scope.form.adress;        console.log(address);        geo.geocode({ 'address': address }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Status geocoder OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);                var mapProp = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };                var map = new google.maps.Map(document.getElementById("map"), mapProp);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });
                // say success with marker payload.
                resolve(marker);            } else {
                // Say error with marker payload.
                reject(status);
            }
        });
    });
}$scope.findLocations = function () {    var dist = 0.1;
    getLatLong()
    .then(function(marker) {
        // Here you receive marker defer by promise, this code will be execute when "resolve" is call on your getLatLong() method
        $http.get('/api/locations/findByLocation/'+$scope.form.lng+'/'+$scope.form.lat+'/'+dist)
        .success(function(data) {
            $scope.locations = data;
            $scope.form = {};
            console.log("locations: ", data);
        })
        .error(function(data) {
            console.log('Error: ' + data);
        });    })
    .catch(function(error) {
        console.log(error)
    });
};

Официальное обещание api

угловое 1 выполнение обещания

jjabba ответил: 28 марта 2018 в 04:35

Я предпочитаю работать с цепочками "это", "то", "то" в javascript, используя обещания. Это что-то вроде кривой обучения, но она делает простой поддерживаемый код при работе с асинхронными вызовами API. Начните с включения зависимости $ q в ваш angular сервис? (из кода, размещенного внутри, неясно, какой angular компонент выполняются ваши звонки).

Вот как это будет выглядеть в вашем примере:

 getLatLong()
 .then(function(longLat) {
      // process answer here
      $http.get('/api/locations/findByLocation/'+$scope.f...
      ...
      return something;
 })
 .then(function(something) {
      // so something more
 });
Marafon Thiago ответил: 28 марта 2018 в 04:37

Вызов geo.geocode({'address':address},function(results, status){...} является асинхронным вызовом. Это означает, что он вызовет API Карт Google, и следующие строки вашего кода будут выполнены без ожидания ответа.

Вторым параметром этого вызова является обратный вызов: function(results, status){...} , Этот обратный вызов является функцией, которая будет выполняться только после того, как асинхронный вызов завершит свой процесс.

Чтобы выполнить вызов на ваш сервер после возврата API Карт Google, вам необходимо кодировать этот вызов внутри обратного вызова. Примерно так:

geo.geocode({'address':address},function(results, status){
    if (status == google.maps.GeocoderStatus.OK) {
        console.log("Status geocoder OK");
        $scope.form.lat = results[0].geometry.location.lat();
        $scope.form.lng = results[0].geometry.location.lng();        var latlng = new google.maps.LatLng($scope.form.lat,$scope.form.lng);        var mapProp = {
                center:latlng,
                zoom:18,
                mapTypeId:google.maps.MapTypeId.ROADMAP,
                mapTypeControl: false
        };        var map=new google.maps.Map(document.getElementById("map"),mapProp);
        var marker = new google.maps.Marker({
                position: latlng,
                map: map,
                title:name
        });        //call the server at this point...
        //http.request(options, function(response){...})    } else {
        alert(status);
    }  });

Вы можете найти больше информации о http-вызове здесь.