Autor Zpráva
hypot
Profil
Snažím se porozumět slibům (promises) a když už jsem myslel, že aspoň tomu základnímu rozumím, hned mě jedna věc zaskočila.
Následující cvičný kód vypíše do konzole text promise a, pak pět vteřin počká, pak vypíše další text promise b, pak zase počká pět vteřin a nakonec vypíše poslední (třetí) text promise c:
        new Promise(function(resolve) {
            resolve("promise a");
        }).then((z_a) => {
            console.log(z_a);
            return new Promise(function(resolve) {
                setTimeout(function() {
                    resolve("promise b");
                }, 5000);
            });
        }).then((z_b) => {
            console.log(z_b);
            return new Promise(function(resolve) {
                setTimeout(function() {
                    resolve("promise c");
                }, 5000);
            });
        }).then((z_c) => {
            console.log(z_c);
        })
S tímto jsem si jen trochu pohrál tak, že jsem tři příslušné objekty vytvořil zvlášť jako hodnoty funkcí:
        function a() {
            return new Promise(function(resolve) {
                resolve("promise a");
            })
        };

        function b() {
            return new Promise(function(resolve) {
                setTimeout(function() {
                    resolve("promise b");
                }, 5000);
            })
        };

        function c() {
            return new Promise(function(resolve) {
                setTimeout(function() {
                    resolve("promise c");
                }, 5000);
            })
        };

        a().then((z_a) => {
            console.log(z_a);
            return b();
        }).then((z_b) => {
            console.log(z_b);
            return c();
        }).then((z_c) => {
            console.log(z_c);
        })
Tato varianta B funguje stejně jako varianta A, to znamená, že nejprve se do konzole hned vypíše promise a, po pěti vteřinách promise b a po dalších pěti vteřinách promise c.
Pak jsem si řekl, že slib je objekt a že si to proto můžu ještě trochu upravit (ušetřím závorky) a zapíšu to takto:
        var a = new Promise(function(resolve) {
            resolve("promise a");
        });

        var b = new Promise(function(resolve) {
            setTimeout(function() {
                resolve("promise b");
            }, 5000);
        });

        var c = new Promise(function(resolve) {
            setTimeout(function() {
                resolve("promise c");
            }, 5000);
        });

        a.then((z_a) => {
            console.log(z_a);
            return b;
        }).then((z_b) => {
            console.log(z_b);
            return c;
        }).then((z_c) => {
            console.log(z_c);
        })
Tato varianta C však dává jiný výsledek: nejprve se do konzole ihned vypíše promise a a pak po pětivteřinové přestávce zároveň promise b a promise c.
Koukal jsem na to dlouho, ale nebyl jsem schopen přijít na to, čím se od sebe varianta B a varianta C z hlediska funkčnosti liší.
Čím tedy?
Radek9
Profil
hypot:
Liší se to v tom, že v poslední ukázce se ty timeouty spustí ihned (tzn. rovnou při definici těch promisů na řádcích 5 a 11). Což nemusí být nutně špatně.

Zkus si to představit jinak: Chceš načíst seznam uživatelů a potom data o jednom konkrétním uživateli. V tu chvíli použiješ model podle tvé první či druhé ukázky, protože potřebuješ nejdřív ten seznam uživatelů, abys mohl spustit další požadavek. Takže voláš:
loadUsers()
.then(function (users) {
  console.log(users)
  return loadSingleUserData(users[0]) // Požadavek (nebo timeout) se spustí až tady
})
.then(function (userData) {
  console.log(userData)
})

Pokud to jsou ale nezávislé požadavky, můžeš je spustit zároveň (tvoje třetí ukázka):
const a = loadSingleUserData(123) 
const b = loadSingleUserData(456)
// oba požadavky (nebo timeouty) se už spustily

a
.then(function (userA) {
  console.log(userA)
  return b
})
.then(function (userB) {
  console.log(userB)
})

Nicméně v tuhle chvíli úplně nedává smysl řetězení (protože jsou ty požadavky nezávislé). Lepší je použít funkci Promise.all, která ti vrátí oba výsledky zároveň:
const a = loadSingleUserData(123) 
const b = loadSingleUserData(456)
// oba požadavky (nebo timeouty) se už spustily

Promise.all([a, b])
.then(function ([userA, userB]) {
  console.log(userA)
  console.log(userB)
})

Jednoduše řečeno tedy prostě záleží, kdy ten promise vytvoříš. Pokud ti záleží na doběhnutí předchozích, musíš ho vytvořit až potom. Pokud ti na tom nezáleží, můžeš je vytvořit všechny současně.
hypot
Profil
Já se obávám, že to, čemu nerozumím, potom ani tak nesouvisí se sliby. Stále totiž nerozumím tomu, proč se v mé variantě B ty timeouty nespustí hned, kdežto ve variantě C se spustí hned.
Když udělám přehled použití metody setTimeout:

A) setTimeout(() => console.log("nějaký text"), 5000) : timeout se spustí hned
B) const a = setTimeout(() => console.log("nějaký text"), 5000) : timeout se spustí hned
C) const a = () => setTimeout(() => console.log("nějaký text"), 5000) : timeout se nespustí hned
D) const objekt = {a: setTimeout(() => console.log("nějaký text"), 5000)} : timeout se spustí hned
E) const objekt = {a: () => setTimeout(() => console.log("nějaký text"), 5000)} : timeout se nespustí hned
F) function a() {setTimeout(() => console.log("nějaký text"), 5000)}: timeout se nespustí hned

A jestliže mám
const a = Promise((...) => setTimeout(() => resolve("nějaký text"), 5000))
domníval jsem se, že to odpovídá variantě C).
Radek9
Profil
hypot:
proč se v mé variantě B ty timeouty nespustí hned, kdežto ve variantě C se spustí hned.
Protože ta funkce, kterou předáváš do Promise, se spouští okamžitě. Takže v B se spustí, až když se ten promise vytvoří (tedy po zavolání příslušné funkce a, b nebo c). V C vytváříš promise rovnou, proto se i timeout spustí rovnou.

A jestliže mám
const a = Promise((...) => setTimeout(() => resolve("nějaký text"), 5000))
domníval jsem se, že to odpovídá variantě C
Neodpovídá. Jak jsem psal výše, ta funkce, kterou předáš, se volá hned. Ten promise nezajímá, jestli na něj něco čeká. Prostě to rovnou provede. Odpovídá to A, B nebo D.
Kajman
Profil
hypot:
Definováním funkce se její obsah nespustí. Obsah se spustí až jejím spuštěním.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0