Czy return może działać asynchronicznie ?

0

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

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 ?

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.

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ł.

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.

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:

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

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

0

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

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

0

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

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)});

1 użytkowników online, w tym zalogowanych: 0, gości: 1