Як чекати, коли обіцянка закінчиться, перш ніж повернути змінну функції?


149

Я все ще борюся з обіцянками, але досягаю певного прогресу завдяки громаді тут.

У мене проста функція JS, яка запитує базу даних Parse. Він повинен повернути масив результатів, але очевидно, завдяки асинхронності характеру запиту (отже, і обіцянок), функція повертається перед результатами, залишаючи мені невизначений масив.

Що мені потрібно зробити, щоб ця функція чекала результату обіцянки?

Ось мій код:

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

}

3
Ви також можете скористатися функцією async / wait. Node тепер підтримує асинхронізацію / очікування поза коробкою з версії 7.6
Viliam Simko

Відповіді:


66

Замість повернення a resultsArrayви повертаєте обіцянку для масиву результатів, а потім, thenщо на сайті виклику - це має додаткову перевагу абонента, знаючи, що функція виконує асинхронний ввід / вивід. Кодування одночасності в JavaScript засноване на тому - ви можете прочитати це питання, щоб отримати більш широке уявлення:

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

Ви можете побачити більше прикладів використання обіцянок розбору з запитами у власному дописі про блог Parse .


ви можете мені сказати, яка підтримка в цьому? IE9 підтримує це?
сандріна-р

Так, але сам Парсе здебільшого мертвий, тому є @SandrinaPereira. Це хмарний код розбору .
Бенджамін Груенбаум

1
Так це не тільки чистий JavaScript? Я шукав спосіб це зробити (чекаю, коли функція закінчиться, щоб почати іншу), але тільки з чистим JavaScript ..
sandrina-p

Питання стосується коду розбору, а не обіцянок. Обіцянки можуть працювати (з бібліотекою) у будь-якому браузері. Bluebird працює в IE6 та netscape 7.
Бенджамін Груенбаум

1
Я вже два дні читаю ТА, і досі ніхто цього не вирішив. Ця прийнята відповідь така ж, як і у всіх інших. Функція повертає Обіцянку, а не значення, як вимагає ОП. Чому ця відповідь позначена як прийнята?
iGanja

19

Що мені потрібно зробити, щоб ця функція чекала результату обіцянки?

Використовуйте async/await(НЕ є частиною ECMA6, але доступна для Chrome, Edge, Firefox та Safari з кінця 2017 року, див. CanIuse )
MDN

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

Додано через коментар: Функція асинхронізації завжди повертає обіцянку, а в TypeScript це виглядатиме так:

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

4
Функція асинхронізації все одно поверне об'єкт обіцянки, якщо його викликають без очікування (або в неасинхронному коді). Перевірте результат console.log (waitForPromise ()), якщо ви не впевнені. Перевірка console.log (результат) у функції асинхронної буде друкувати то , що ви очікуєте, але повернення з функції асинхронної відбувається відразу , без блокування і повертає обіцянку. Заблокування в JavaScript зазвичай дуже погано, оскільки це однопоточне додаток, і блокування буде голодувати за будь-якими іншими паб / підзахисними клієнтами сповіщень, фактично доводячи всю програму до колін.
SRM

1
.net має .wait () на "обіцянку", як клас завдань. У Javascript відсутня ця функція? Мені потрібно почекати чогось, перш ніж вийти з інструменту командного рядка вузла, який може передавати його вихід іншому інструменту. "очікувати" працює лише всередині функцій асинхронізації. Це означає, що це не працює поза межами обіцянки.
TamusJRoyce

@SRM Я відчуваю, що ваш коментар заснований на неправильному трактуванні зразка - мова йде про "внутрішній" Promise.resolve (як найпростіший приклад Promise), тому немає зовнішнього абонента, як ви заявляєте у своєму коментарі. Тому я вирішив оновити відповідь.
Мартін Мізер

@TamusJRoyce Здогадайтесь, це питання самостійно, але я думаю, що в C # ви можете використовувати Task.ContinueWith (Завдання), що є тією ж ідеєю, що ви бачите у прийнятій відповіді (де вона називається "тоді ()").
Мартін Мізер

Я думаю, що зараз бачу. Я можу в значній мірі обернути весь свій сценарій однією величезною функцією асинхронізації. І називати цю функцію останнім рядком мого сценарію. Ця функція все одно була б трохи плитою котла. Але набагато менше, ніж я раніше сприймав. Я не звик писати функції в межах функцій. Дякую @MartinMeeser!
TamusJRoyce

3

Ви не хочете змушувати функцію чекати, тому що JavaScript призначений не блокувати. Швидше поверніть обіцянку в кінці функції, тоді функція виклику може використовувати обіцянку, щоб отримати відповідь сервера.

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

//Or return query.find(); 

1
Уся річ з зворотними викликами зі success:шматочком відключена.
Бенджамін Груенбаум

Або краще: return query.find();.
маш

Також добре. Я просто залишу це для наочності, але додаю його як коментар.
Простежте

Я спробував це, але результати здаються невизначеними. resultsByName ("ім'я"). тоді (функція (результати) {console.log ("отримав масив" + results.count);});
mac_55

1
Дякую, у функції результатів повинна бути якась помилка. Зараз це працює. Я змінив console.log на results.length і бачу, що у моєму поверненому масиві є 1 запис :)
mac_55

2

Ви фактично не використовуєте тут обіцянок. Аналіз дозволяє використовувати зворотні дзвінки або обіцянки; твій вибір.

Щоб використовувати обіцянки, виконайте наступне:

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

Тепер, щоб виконати матеріал після завершення обіцянки, ви можете просто виконати його всередині зворотного виклику обіцянки всередині then()виклику. Поки що це було б точно так само, як і звичайні зворотні дзвінки.

Насправді добре використати обіцянки - це коли ви їх ланцюгуєте так:

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

Який тип об’єкта є об'єктом результатів? оскільки він, схоже, не містить мого масиву
mac_55

Це має бути масив Parse.Objects.
маш
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.