Czy return może działać asynchronicznie ?

Czy return może działać asynchronicznie ?
adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:6 dni
  • Postów:318
0

Cześć
Mam taki kod
Który dodaje mi do obiektu staff losowe listy, komentarze i posty:

Kopiuj
var stuff = (function(obj) {
  const adress = "https://jsonplaceholder.typicode.com";
  fetch(adress + "/todos/")
    .then(response => response.json())
    .then(json => (obj.todos = json));
  fetch(adress + "/comments/")
    .then(response => response.json())
    .then(json => (obj.comments = json));
  fetch(adress + "/posts/")
    .then(response => response.json())
    .then(json => (obj.posts = json));
  return obj;
})({});
console.log(stuff);

Zastanawia mnie jednak dlaczego ten kod działa.
Czemu return nie zwraca pustego obiektu, przecież zaciągnięcie danych odbywa się asynchronicznie a
return powinno się wykonać zanim pobiorę dane z serwera ?

edytowany 1x, ostatnio: adams0
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:prawie 2 lata
  • Lokalizacja:Wrocław
  • Postów:13042
3

stuff początkowo jest pustym obiektem - rzecz w tym, że gdy w przeglądarce naciskasz przycisk rozwijający jego zawartość, ta stara się być sprytna i sprawdza czy przypadkiem obiekt nie został w międzyczasie zmodyfikowany.

Zmień sobie console.log(stuff); na console.log(stuff.hasOwnProperty('todos')); a zobaczysz, że zwraca false.


edytowany 2x, ostatnio: Patryk27
Haskell
  • Rejestracja:prawie 10 lat
  • Ostatnio:12 miesięcy
  • Postów:4700
3

Ale skąd wiesz, że ten kod działa? Napisz sobie conosle.log(stuff.todos) i przekonaj się, że jednak nie działa :D

Po prostu od momentu gdy zdążysz rozwinać klamerki tego obiektu w konsoli dane się pobiorą, ponieważ to trwa w tym przypadku około 60 milisekund na zapytanie. Czyli jesteś zbyt wolny kowboju, na dzikim zachodzie już byś dawno zginął od rewolwerowej kuli pierwszego lepszego rzezimieszka.

//edit: w trakcie pisania już mnie @Patryk27 ubiegł.


Zaglądali do kufrów, zaglądali do waliz, nie zajrzeli do d**y - tam miałem socjalizm. Czesław Miłosz
edytowany 1x, ostatnio: Haskell
adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:6 dni
  • Postów:318
0

Myślałem że muszę deklarować funkcję w jakiś specjalny sposób żeby return czekało aż promisy się wykonają (spotkałem się z zapisem async przed funkcją) ? Myślałem że return nie poczeka i zwyczajnie zwróci pusty obiekt.

edytowany 2x, ostatnio: adams0
AQ
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:23
1

Return zwraca pusty obiekt, ale zanim rozwiniesz obiekt w konsoli, to wykonywane promisy przypisują do tego samego obiektu właściwości.
Analogiczny przykład:

Kopiuj
const ret = {};
console.log(ret)
ret.test = true

https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:6 dni
  • Postów:318
0

Racja! Zapomniałem że obiekty są typem referencyjnym. Wielkie dzięki.

Haskell
  • Rejestracja:prawie 10 lat
  • Ostatnio:12 miesięcy
  • Postów:4700
0

Ale ten return nie czeka. Return natychmiast zwraca pusty obiekt obj przekazany w parametrze wywołania funkcji. Ten pusty obiekt jest zapisywany do zmiennej stuff. Natomiast fetch zwraca Promise czyli obiekt reprezentujący wykonanie lub błąd wykonania asynchronicznego kodu. Z kolei then sprawia, że tworzysz kolejny Promise. Taki asynchroniczny kod z tego ostatniego Promise trafia sobie do pętli zdarzeń. Kiedy w końcu dane zostaną pobrane ten kod się wykonuje czyli do istniejącego już obiektu obj, którego trzymasz sobie w zmiennej stuff zostają zapisane właściwości todos, comments, posts.

Czyli teraz wszystko zależy od tego, kiedy zajrzysz do tego stuff. Jeżeli zajrzysz natychmiast to tam nic nie będzie, jeżeli zajrzysz po kilkudziesięciu milisekundach to kod z pętli zdarzeń już zdąży się wykonać i pojawią się podane wyżej właściwości.

//edit: znów mnie @Aqu wyprzedził :P


Zaglądali do kufrów, zaglądali do waliz, nie zajrzeli do d**y - tam miałem socjalizm. Czesław Miłosz
edytowany 2x, ostatnio: Haskell
M3
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 3 lata
  • Postów:195
0

Jeśli chcesz żeby to naprawdę działało, to trzeba czegoś w tym stylu:

Kopiuj
async function stuff() {
    const adress = 'https://jsonplaceholder.typicode.com';
    const todos = fetch(`${adress}/todos/`).then(response => response.json());
    const comments = fetch(`${adress}/comments/`).then(response => response.json());
    const posts = fetch(`${adress}/posts/`).then(response => response.json());
  
    const obj = {};
    [obj.todos, obj.comments, obj.posts] = await Promise.all([todos, comments, posts]);
    return obj;
}

stuff().then((obj) => { console.log(obj)});

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.