Javascript-форум (https://javascript.ru/forum/)
-   Javascript под браузер (https://javascript.ru/forum/css-html/)
-   -   Как сделать функцию асинхронной, если она состоит из нескольких функций в js? (https://javascript.ru/forum/css-html/83365-kak-sdelat-funkciyu-asinkhronnojj-esli-ona-sostoit-iz-neskolkikh-funkcijj-v-js.html)

mav1 23.11.2021 10:13

Как сделать функцию асинхронной, если она состоит из нескольких функций в js?
 
У меня есть подобная функция:

function addressToCoords(local) {
    var address = local;
    var result = '';
    geocoder.geocode( { 'address': address}, function(results, status) {
        
      if (status == 'OK') {
         result = results[0].geometry.location;
      } else {
        console.log('Error: ' + status);
         result = '';
      }
        alert('Result is '+result);
    });
        
    alert('Result2 is '+result);
    return result;
  }


Так как для выполнения геокодирования необходимо некоторое время, сначала выводится сообщение "Result2 is ", и только после этого сообщение "Result is {координаты}" , ну и функция возвращает пустышку вместо {координат}. Как я понимаю, я должен сделать так, чтобы функции выполнялись асинхронно. Вижу в документации js на сайте мозиллы подобный пример:

async function f() {
  return 1;
}
f().then(alert);


Но как быть в моем случае с geocoder.geocode...?

Aetae 23.11.2021 10:32

function asyncGeocode(params) {
  return new Promise((resolve, reject) => geocoder.geocode(
    params, 
    (results, status) => status === 'OK' ? resolve(results) : reject(status)
  ));
}

async function addressToCoords(local) {
  var address = local;
  var result = await asyncGeocode({address}).catch(status => {
    console.log('Error: ' + status);
    return '';
  });

  alert('Result is ' + result);
  return result;
}

Подробнее...

mav1 23.11.2021 11:26

Пример, приведенный вами, видимо рабочий, однако что делать с результатом выполнения функции addressToCoords(), если :

var coords = addressToCoords('some string with location');
alert(coords);


показывает мне:

[object Promice]

voraa 23.11.2021 12:23

Либо
var coords = await addressToCoords('some string with location');
alert(coords)
Либо
addressToCoords('some string with location').then (coords => alert(coords));

Aetae 23.11.2021 12:29

mav1, что делать - в ссылке "подробнее".

mav1 23.11.2021 14:13

Цитата:

Сообщение от voraa (Сообщение 541783)
Либо
var coords = await addressToCoords('some string with location');
alert(coords)

Этот вариант не работает, пишет что await не может быть для async-функции. Ведь до этого в коде указано, что async addressToCoords...

Цитата:

Сообщение от voraa (Сообщение 541783)
addressToCoords('some string with location').then (coords => alert(coords));

А этот не работает, так как "coords" не определено

mav1 23.11.2021 14:22

Вроде бы должно быть что-то наподобие (судя по примерам с ссылки "подробнее"):

addressToCoords('some string with location').then(alert(result));


Ведь алерт уже выводится после того, как выполнилась addressToCoords(), и, стало быть, result уже должна быть определена. Но увы, не так.

voraa 23.11.2021 15:02

Цитата:

Сообщение от mav1
Этот вариант не работает, пишет что await не может быть для async-функции. Ведь до этого в коде указано, что async addressToCoords...

Вы наверно читать не умеете.
Там скорее всего написано, что await может быть ТОЛЬКО в async функциях.
Это действительно так. Поэтому функция, где используется await, тоже должна быть объявлена, как async.
Если такой функции нет (код исполняется на верхнем уровне скрипта), то приходится делать фиктивную функцию и тут же ее вызывать
[QUOTE=mav1]Сообщение от voraa 
addressToCoords('some string with location').then (coords => alert(coords));
А этот не работает, так как "coords" не определено[/QUOTE]


Вы сами пробовали, что не работает?
зачем определять coords, если это формальный параметр фунции передаваемой в then?

mav1 23.11.2021 15:59

Пробовал вот в этом примере: http://95.174.111.242:8091/maptest/test.php

Полный код данной тестовой странички:

<html>
<head>
<title>Geocode example</title>
</head>
<body>
<p>map</p>
<style>
html,
body,
#map_canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
</style>

<script src="https://maps.googleapis.com/maps/api/js?key=key"></script>
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>

<script>
	


var geocoder;
var map;
var bounds = new google.maps.LatLngBounds();

function initialize() {
	geocoder = new google.maps.Geocoder();
  map = new google.maps.Map(
    document.getElementById("map_canvas"), {
      center: new google.maps.LatLng(41.92233950111221, 12.442120355172237),
      zoom: 13,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });

  
}
	
initialize();
	
	function asyncGeocode(params) {
		alert('asyncGeocode started with params: '+params);
  return new Promise((resolve, reject) => geocoder.geocode(
    params, 
    (results, status) => status === 'OK' ? resolve(results) : reject(status)
  ));
}

async function addressToCoords(loc) {
  var address = loc;
  var result = await asyncGeocode(address).catch(status => {
    console.log('Error: ' + status);
    return '';
  });
  alert('now here');
  alert('Result is ' + result);
  return result;
}

	addressToCoords('Rome, Italy').then (coords => alert(coords));
	alert(result);
	
	
</script>
</body>
</html>


Должен сработать
alert('Result is ' + result);
однако его не вижу

voraa 23.11.2021 17:52

А что видите?
В консоле ошибок нет?

mav1 23.11.2021 18:32

Хочу видеть вывод координат, но в консоли:

test.php:63 Uncaught ReferenceError: result is not defined

voraa 23.11.2021 18:44

Цитата:

Сообщение от mav1
Пробовал вот в этом примере: http://95.174.111.242:8091/maptest/test.php

Там ошибка лезет
Google Maps JavaScript API error: RefererNotAllowedMapError

У вас есть платный аккаунт в Google Maps, Этот IP к нему привязан?

voraa 23.11.2021 18:50

Цитата:

Сообщение от mav1
Хочу видеть в консоли вывод координат, но там:

А Вам кто-нибудь показывал такой пример
addressToCoords('Rome, Italy').then (coords => alert(coords));
	alert(result);

Я писал просто
addressToCoords('Rome, Italy').then (coords => alert(coords));

Координаты должны быть в coords.
Если сам Google Maps у вас нормально работает.

mav1 23.11.2021 19:09

Пробовал и как вы написали, и с дополнительным алертом в конце - все равно координаты не выводит никоим образом. Ограничения гугловые айпишные убрал временно.

Ваш вариант: http://95.174.111.242:8091/maptest/test2.php
Вариант с добавочным алертом в конце: http://95.174.111.242:8091/maptest/test.php

рони 23.11.2021 19:36

mav1,
geocoder.geocode + promise:

voraa 23.11.2021 19:48

В geocode должна передаваться не просто строка с адресом, а объект
https://developers.google.com/maps/d...rence/geocoder
https://developers.google.com/maps/d...eocoderRequest

Вот тут они показывают пример
https://developers.google.com/maps/d...ript/geocoding
geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == 'OK') {

Попробуйте вызывать
addressToCoords({address:'Rome, Italy'}).then (coords => alert(coords))

mav1 24.11.2021 01:14

В итоге попробовал вот такой вариант:

addressToCoords({address:'Rome, Italy'}).then (coords => alert(coords[0].geometry.location))


и получил необходимые координаты в алерте. Но проблема осталась в их использовании далее - если сразу после данной строки я добавлю, к примеру:

alert(coords[0].geometry.location);


то при запуске страницы у меня сначала будет выводиться этот алерт (разумеется, undefined, ведь addressToCoords еще не успела сработать), а только потом будет срабатывать уже addressToCoords() со своим алертом (уже с координатами).

Как теперь добавить код, который будет использовать полученные координаты, чтобы он срабатывал только ПОСЛЕ того, как отработает addressToCoords() ? Не запихивая его внутрь самой addressToCoords() или в .then()

Aetae 24.11.2021 01:42

mav1, ты бы уже десять раз успел прочитать учебник если бы в стену головой не долбился.

Асинхронные функции работают только с асинхронными, синхронные с синхронными. Всё. Совместить - никак.
1. Ты делаешь асинхронный запрос к геокодеру.
2. Ты ничего не ждёшь, а сразу делаешь alert.
3. Идёт время.
4. Приходит ответ геокодера.

Почему же alert ничего не показал, а?

Что и как делать - расписано в учебнике, конкретное решение проблемы также предложено в этой теме.

Ты хочешь готовый код и не хочешь думать? Ну извини, попробуй поставить задачу на фрилансе.

mav1 24.11.2021 01:42

запихал все в .then() и обрел дзен. Работает, и ладно. Не очень чтоб накладно

mav1 24.11.2021 01:44

Цитата:

Сообщение от Aetae (Сообщение 541808)
Асинхронные функции работают только с асинхронными, синхронные с синхронными.

Да, это вроде уложилось теперь в голове, статью почитал

voraa 24.11.2021 08:02

В документации
https://developers.google.com/maps/d...rence/geocoder
сказано, что сама geocode возвращает Promise с результатом.
Тогда эти функции можно так переписать

async function Geocode(params) {
     alert('asyncGeocode started with params: '+params);
	let resp = await geocoder.geocode(params);
        return resp.results;
}
 
async function addressToCoords(loc) {
  var results = await async Geocode({address: loc}).catch(status => {
				console.log('Error: ' + status);
				return '';
			});
  alert('Result is ' + results);
  return results;
}

Правда, непонятно, что с ошибкой, где status возвращается. В документации не слова

Aetae 24.11.2021 13:38

voraa, как ты в эти доки попал? Я не юзаю доки гугла обычно и дотыкать до референс вообще сходу не смог без прямой ссылки.)

voraa 24.11.2021 16:06

Цитата:

Сообщение от Aetae
voraa, как ты в эти доки попал?

Google "geocoder.geocode"
Ну и там первые ссылки
А потом по их ссылкам.

Aetae 24.11.2021 16:27

Цитата:

Сообщение от voraa (Сообщение 541823)
Google "geocoder.geocode"
Ну и там первые ссылки
А потом по их ссылкам.

Дык я так и сделал. С той же целью, посмотреть может там есть промис из коробки.)
Пару минут потыкал, плюнул и забил, вникать и прямо читать весь этот мусор лень было.)
Хреновый UX. =\


Часовой пояс GMT +3, время: 19:14.