Как мне дождаться завершения обещания, прежде чем возвращать переменную функции?


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 / await. Node теперь поддерживает async / await из коробки, начиная с версии 7.6
Вильям Симко

Ответы:


66

Вместо возврата 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 поддерживает это?
Сандрина-п

Да, но сам Parse в основном мертв, так что есть @SandrinaPereira. Это разбор облачного кода.
Бенджамин Грюнбаум

1
Ах, так что это не только чистый JavaScript? Я искал способ сделать это (ждать завершения функции, чтобы запустить другую), но только с чистым javascript ..
sandrina-p

Вопрос в разборе кода, а не в обещаниях. Обещания могут работать (с библиотекой) в любом браузере. Bluebird работает в IE6 и netscape 7.
Бенджамин Грюнбаум

1
Я читаю ТАК два дня, и все же, никто не решил это. Этот принятый ответ такой же, как и любой другой. Функция возвращает Promise, а не значение, запрошенное OP. Почему этот ответ помечен как принятый?
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');
    }

Добавлено из-за комментария: асинхронная функция всегда возвращает 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 (result) в асинхронной функции выведет то, что вы ожидаете, но возврат из асинхронной функции происходит немедленно без блокировки и возвращает обещание. Блокировка в javascript, как правило, очень плохая, так как это однопоточное приложение, и блокирование приведет к тому, что любые другие паб / суб-клиенты будут лишены уведомлений, по сути, ставя все приложение на колени.
SRM

1
.net имеет .wait () в классе задач типа «обещание». В Javascript отсутствует эта функция? Мне нужно что-то подождать, прежде чем выходить из моего инструмента командной строки узла, который может передать свой вывод другому инструменту. «Ожидание» работает только внутри асинхронных функций. То есть это не работает вне рамок обещания.
TamusJRoyce

@ SRM Я чувствую, что ваш комментарий основан на неправильной интерпретации образца - он касается «внутреннего» Promise.resolve (как наиболее простой пример Promise), поэтому нет внешнего вызывающего абонента, который вы указали в своем комментарии. Поэтому я решил обновить ответ.
Мартин Мизер,

@TamusJRoyce Думаю, что это вопрос сам по себе, но я думаю, что в C # вы можете использовать Task.ContinueWith (Task), что является той же идеей, что вы видите в принятом ответе (где он называется «then ()»).
Мартин Мизер,

Я думаю, что я вижу сейчас. Я могу в значительной степени обернуть весь сценарий в одну огромную асинхронную функцию. И вызвать эту функцию в качестве последней строки моего сценария. Эта функция по-прежнему будет немного от плиты котла. Но гораздо меньше, чем я раньше воспринимал. Я не привык писать функции внутри функций. Спасибо @MartinMeeser!
TamusJRoyce

3

Вы не хотите заставлять функцию ждать, потому что JavaScript должен быть неблокирующим. Вместо этого верните обещание в конце функции, тогда вызывающая функция может использовать обещание, чтобы получить ответ сервера.

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

//Or return query.find(); 

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

Или лучше: return query.find();.
пюре

Также хорошо Я просто оставлю это в качестве иллюстрации, но добавлю это как комментарий.
Трассировка

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

1
Спасибо, должно быть была какая-то ошибка внутри функции результатов. Теперь работает. Я изменил свой console.log на results.length и вижу, что в моем возвращенном массиве есть 1 запись :)
mac_55

2

Вы на самом деле не используете обещания здесь. Parse позволяет использовать обратные вызовы или обещания; твой выбор.

Чтобы использовать обещания, сделайте следующее:

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.