Jak czekać na zakończenie obietnicy przed zwróceniem zmiennej funkcji?

149

Wciąż zmagam się z obietnicami, ale robię postępy dzięki społeczności tutaj.

Mam prostą funkcję JS, która wysyła zapytania do bazy danych Parse. Ma zwrócić tablicę wyników, ale oczywiście ze względu na asynchroniczny charakter zapytania (stąd obietnice) funkcja zwraca przed wynikami, pozostawiając mnie z niezdefiniowaną tablicą.

Co muszę zrobić, aby ta funkcja czekała na wynik obietnicy?

Oto mój kod:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find({
               success: function(results) {
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               },

               error: function(error) {
               // error is an instance of Parse.Error.
                             console.log("Error");
               }
    });                           

}
mac_55
źródło
3
Możesz również rozważyć użycie async / await. Węzeł obsługuje teraz async /
await po

Odpowiedzi:

66

Zamiast resultsArrayzwracać a, zwracasz obietnicę dla tablicy wyników, a następnie thentę w witrynie wywołania - ma to dodatkową zaletę, że wywołujący wie, że funkcja wykonuje asynchroniczne operacje we / wy. Na tym opiera się współbieżność kodowania w JavaScript - możesz przeczytać to pytanie, aby uzyskać szersze pojęcie:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find({});                           

}

// later
resultsByName("Some Name").then(function(results){
    // access results here by chaining to the returned promise
});

Więcej przykładów użycia obietnic parsowania z zapytaniami można znaleźć we własnym poście w blogu Parse na ten temat .

Benjamin Gruenbaum
źródło
czy możesz mi powiedzieć, jakie jest tego wsparcie? IE9 to obsługuje?
sandrina-p
Tak, ale sama Parse jest w większości martwa, więc jest to @SandrinaPereira. To jest parsowanie kodu w chmurze .
Benjamin Gruenbaum
1
Ach, więc to nie jest tylko czysty javascript? Szukałem sposobu, aby to zrobić (poczekaj na zakończenie funkcji, aby uruchomić inną), ale tylko z czystym javascriptem ..
sandrina-p
Pytanie dotyczy kodu parsowania, a nie obietnic. Obietnice mogą działać (z biblioteką) w dowolnej przeglądarce. Bluebird działa w IE6 i netscape 7.
Benjamin Gruenbaum
1
Czytam SO od dwóch dni i nadal nikt tego nie rozwiązał. Ta zaakceptowana odpowiedź jest taka sama jak każda inna. Funkcja zwraca Obietnicę, a nie wartość żądaną przez OP. Dlaczego ta odpowiedź została oznaczona jako zaakceptowana?
iGanja
19

Co muszę zrobić, aby ta funkcja czekała na wynik obietnicy?

Użyj async/await(NIE jest częścią ECMA6, ale dostępne dla Chrome, Edge, Firefox i Safari od końca 2017 r., Patrz canIuse )
MDN

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

Dodano komentarz: Funkcja asynchroniczna zawsze zwraca Obietnicę, aw TypeScript wyglądałaby tak:

    async function waitForPromise(): Promise<string> {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }
Martin Meeser
źródło
4
Funkcja asynchroniczna nadal zwraca obiekt obietnicy, jeśli zostanie wywołana bez oczekiwania (lub w kodzie nieasynchronicznym). Sprawdź wynik console.log (waitForPromise ()), jeśli nie jesteś pewien. Sprawdzenie console.log (wynik) wewnątrz funkcji asynchroniczny będzie wydrukować, czego się spodziewać, ale powrót z funkcji asynchronicznej dzieje się natychmiast, bez blokowania i wraca obietnicę. Blokowanie w javascript jest zwykle bardzo złe, ponieważ jest to aplikacja jednowątkowa, a blokowanie spowoduje głodzenie powiadomień przez innych klientów pub / sub, zasadniczo sprowadzając całą aplikację na kolana.
SRM
1
.net ma .wait () na "obietnicy", takiej jak klasa task. Czy JavaScript brakuje tej funkcji? Muszę na coś poczekać, zanim wyjdę z narzędzia wiersza polecenia węzła, które może przesłać dane wyjściowe do innego narzędzia. „await” działa tylko wewnątrz funkcji asynchronicznych. Oznacza to, że nie działa poza zakresem obietnicy.
TamusJRoyce
@SRM Wydaje mi się, że twój komentarz jest oparty na błędnej interpretacji próbki - dotyczy "wewnętrznego" Promise.resolve (jako najprostszego przykładu Promise), więc nie ma zewnętrznego dzwoniącego, jak stwierdzasz w swoim komentarzu. Postanowiłem więc zaktualizować odpowiedź.
Martin Meeser
@TamusJRoyce Zgadnij, że jest to pytanie samo w sobie, ale myślę, że w C # możesz użyć Task.ContinueWith (Task), co jest tym samym pomysłem, co widzisz w zaakceptowanej odpowiedzi (gdzie nazywa się to "then ()").
Martin Meeser
Myślę, że teraz rozumiem. Prawie mogę owinąć cały skrypt w jedną ogromną funkcję asynchroniczną. I wywołaj tę funkcję jako ostatnią linię mojego skryptu. Ta funkcja nadal byłaby trochę płytą kotłową. Ale znacznie mniej niż wcześniej sądziłem. Nie jestem przyzwyczajony do pisania funkcji w funkcjach. Dziękuję @MartinMeeser!
TamusJRoyce
3

Nie chcesz, aby funkcja czekała, ponieważ JavaScript ma nie blokować. Zamiast zwracać obietnicę na końcu funkcji, funkcja wywołująca może użyć obietnicy do uzyskania odpowiedzi serwera.

var promise = query.find(); 
return promise; 

//Or return query.find(); 
Ślad
źródło
1
Cała twoja sprawa callbacków z success:bitem jest wyłączona.
Benjamin Gruenbaum,
Albo lepiej: return query.find();.
zacieru
Też dobrze. Zostawię to w ten sposób dla celów ilustracyjnych, ale dodałem to jako komentarz.
Śledź
Próbowałem tego, ale wyniki wydają się być nieokreślone. resultsByName ("name"). then (function (results) {console.log ("gotowa tablica" + liczba wyników);});
mac_55
1
Dzięki, w funkcji wyników musiał być jakiś błąd. Już działa. Zmieniłem mój console.log na results.length i widzę, że w zwróconej tablicy jest 1 wpis :)
mac_55
2

W rzeczywistości nie używasz tutaj obietnic. Parse pozwala na użycie wywołań zwrotnych lub obietnic; Twój wybór.

Aby skorzystać z obietnic, wykonaj następujące czynności:

query.find().then(function() {
    console.log("success!");
}, function() {
    console.log("error");
});

Teraz, aby wykonać rzeczy po zakończeniu obietnicy, możesz po prostu wykonać ją w wywołaniu zwrotnym obietnicy w then()wywołaniu. Jak dotąd byłoby to dokładnie to samo, co zwykłe wywołania zwrotne.

Aby rzeczywiście dobrze wykorzystać obietnice, należy je połączyć w łańcuch, na przykład:

query.find().then(function() {
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
}, function() {
    console.log("error");
}).then(function() {
    console.log("success on second callback!");
}, function() {
    console.log("error on second callback");
});
zacier
źródło
Jakim typem obiektu jest obiekt wyników? ponieważ wydaje się, że nie zawiera mojej tablicy
mac_55
Powinna to być tablica Parse.Object.
zacieru