вернуть логическое значение после того, как обещание было разрешено/отклонено?

У меня есть функция, которая работает абсолютно нормально. Я просто хочу вернуть true или false в зависимости от обещания.

 //I want this function to return a simple true or false!!!
function isAppOnline() {
            var is_connected = connectivityMonitor.isInternetConnected();
            is_connected.then(function(result) {
                console.log('INTERNET_CHECK_API : app online');//works fine
                return true;//this is not being returned
            }, function(error) {
                console.log('INTERNET_CHECK_API : app offline');//works fine
                return false;//this is not being returned
            });
        }

Но когда я вызываю эту функцию,

is_online = isAppOnline();

is_online всегда undefined . Почему функция не может вернуть простое логическое значение?

Обновление:

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


person HIRA THAKUR    schedule 20.10.2015    source источник
comment
Основываясь на вашем редактировании, вы можете выделить логику этого всплывающего окна в отдельный контроллер, что, вероятно, в любом случае является хорошей идеей. Этот контроллер может размещаться с другим статическим содержимым между страницами, ваша навигация в своем собственном контроллере может работать на том же уровне в приложении, что и этот? тогда вам нужно использовать промис только в одном месте, плюс он более модульный. Единственный повод для беспокойства. Также делает его более тестируемым. вы даже можете поместить его в директиву и просто вставить в свое представление, где хотите.   -  person ste2425    schedule 20.10.2015
comment
этот код для всех контроллеров. :)   -  person HIRA THAKUR    schedule 20.10.2015


Ответы (4)


РЕДАКТИРОВАТЬ: Для ES2017 Если вам повезло, кто использует ES2017, вы можете использовать новый await/async ключевые слова. Они довольно блестящие и позволяют вам писать асинхронный код, который читается синхронно. (Это все еще обещания под капотом, просто их распаковка).

function isOnline() {
    return Promise.resolve(true);
}

async function Main() {
    const online = await isOnline();

  console.log(online);
}

Main();

файл


Потому что он асинхронный. Ваш метод isAppOnline возвращается до того, как ваше обещание будет разрешено.

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

Поэтому, если вы хотите, чтобы вызывающий абонент isAppOnline знал результат, у вас есть варианты. Либо перезвоните, либо верните обещание (лучший вариант)

function isAppOnline(cb) {
    var is_connected = connectivityMonitor.isInternetConnected();
    is_connected.then(function(result) {
        console.log('INTERNET_CHECK_API : app online');//works fine
        cb(true);
    }, function(error) {
        console.log('INTERNET_CHECK_API : app offline');//works fine
        cb(false);
    });
}

//better option
function isAppOnline() {
    return connectivityMonitor.isInternetConnected().then(function(result) {
        console.log('INTERNET_CHECK_API : app online');//works fine
        return true;
    }, function(error) {
        console.log('INTERNET_CHECK_API : app offline');//works fine
        return false;
    });
}

//used as
isAppOnline().then(function (isOnline) {
    console.log('Is it online?', isOnline);
});
person ste2425    schedule 20.10.2015
comment
О какой, второй? Я должен добавить, не видя остальной части вашего кода, что эта конкретная реализация не проверена. Однако принцип работает отлично, я лично использовал этот метод почти в каждом приложении angular, над которым работал. Возврат обещаний из методов, использующих .then(), идеально подходит для цепочки. - person ste2425; 20.10.2015
comment
ага, второй. ну я искал что-то попроще. Я знал, что могу добавить еще одно обещание, но именно поэтому я задал вопрос. Обещание за обещанием за обещанием… нет ли чего-нибудь попроще. В любом случае спасибо. - person HIRA THAKUR; 20.10.2015
comment
@Jayesh Jain Обратите внимание на возврат, добавленный до is_connected - person Icycool; 20.10.2015
comment
@lcycool Ответ отредактирован. Джейеш Джейн. Если вам приходится выполнять промис за промисом во вложенных цепочках промисов, которые изначально связаны с промисами, которые еще не были созданы, вам может потребоваться пересмотреть структуру вашего приложения. - person ste2425; 20.10.2015
comment
ну, это всего лишь одно обещание на моей фабрике .. а затем isAppOnline() в моем .run() . так что есть два обещания. Я не думаю, что у меня плохая структура, мне может понадобиться использовать одну и ту же функцию в нескольких местах. - person HIRA THAKUR; 20.10.2015
comment
Функции, возвращающие промис, самодостаточны — вам не нужно заботиться о вызывающем объекте, что хорошо, если вам нужно вызывать его в разных местах. - person Icycool; 20.10.2015

Промис работает по-другому с простыми операторами, потому что они могут возвращаться позже, поэтому вам может потребоваться переосмыслить поток вашей программы, чтобы обрабатывать разные начальные и конечные состояния.

function isAppOnline() {
    var is_connected = connectivityMonitor.isInternetConnected();
    return is_connected.then(function(result) { // add return here to return the whole promise
        console.log('INTERNET_CHECK_API : app online');//works fine
        return; //this will resolve the promise returned
    }, function(error) {
        console.log('INTERNET_CHECK_API : app offline');//works fine
        $q.reject(); // this will reject the promise returned
    });
}

Вам придется обрабатывать изменяющиеся состояния в вызывающем контроллере (некоторое время оно может быть ложным, а затем становиться истинным и т. д.). Вы можете рассмотреть возможность использования состояния загрузки, чтобы не сбивать пользователей с толку.

is_online = false;
isLoading = true;

isAppOnline().then(function() {
    is_online = true;
}, function() {
    is_online = false;
})
.finally(function(){
    isLoading = false;
});
person Icycool    schedule 20.10.2015

Ваш вопрос указывает на довольно глубокую потребность в дальнейшем изучении асинхронной обработки Javascript. Я рекомендую прочитать: Как вернуть ответ на асинхронный вызов ?

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

person David Boskovic    schedule 20.10.2015
comment
конечно... я добавлю еще несколько моментов, объясняющих, чего я пытаюсь достичь. - person HIRA THAKUR; 20.10.2015

Вы можете попробовать следующее (это непроверенный код, поскольку вы не предоставили рабочий скрипт):

function isAppOnline() {
    var defer = $q.defer();

    var is_connected = connectivityMonitor.isInternetConnected();
    is_connected.then(function(result) {
        console.log('INTERNET_CHECK_API : app online');//works fine
        defer.resolve(true);
    }, function(error) {
        console.log('INTERNET_CHECK_API : app offline');//works fine
        defer.resolve(false);
    });

    return defer.promise;
}

И назовите это так:

var is_online = false;
isAppOnline().then(function(data){
    is_online = data;
});

Или передайте объект is_connected напрямую, чем лучше обрабатывать ошибки:

function isAppOnline() {
    var defer = $q.defer();

    var is_connected = connectivityMonitor.isInternetConnected();
    is_connected.then(function(result) {
        console.log('INTERNET_CHECK_API : app online');//works fine
        defer.resolve(is_connected);
    }, function(error) {
        console.log('INTERNET_CHECK_API : app offline');//works fine
        defer.reject();
    });

    return defer.promise;
}
person Spikee    schedule 20.10.2015
comment
Пожалуйста, обратитесь к моему ответу или ste2425 при возврате обещания, а не создавайте новый отложенный. - person Icycool; 20.10.2015
comment
Таким образом, он готов к более сложному возвращаемому объекту, если вы хотите сделать что-то вроде этого: var result = { isConnected: is_connected, ...}. По моему опыту, лучше всего делать это таким образом, потому что по мере роста вашего приложения вам все равно придется это делать в какой-то момент, поэтому лучше пораньше. - person Spikee; 20.10.2015
comment
Неа. Случай, когда вам действительно нужно создать deferred, — это когда ядро ​​​​функции не возвращает обещание, например $timeout. На самом деле создание отложенного, когда обещание может быть возвращено, определяется как один из promise-antipatterns< /а>. - person Icycool; 20.10.2015
comment
Итак, как вы решаете добавить к существующему результату обещания (просто любопытно)? - person Spikee; 20.10.2015
comment
function f1 = function (p1) { return f2.then(function(res2) { return p1 + res2; }) } И затем в вызывающем: f1('p1').then(function(res1) { // res1 == 'p1' + res2 }) Это просто показывает маршрут разрешения, маршрут отклонения почти такой же, как и при использовании $q.reject. Вы можете сделать что угодно с res2, прежде чем вернуть его как res1. - person Icycool; 20.10.2015
comment
Извините, я не могу понять. Код трудно читать или я не правильно понял ваш вопрос? - person Icycool; 21.10.2015
comment
@Spikee, я не думаю, что ваш аргумент означает более сложный возвращаемый объект. Скажите, что вы возвращаете необработанный ответ от http-вызова, возвращая ответ. Итак, return $http.get() если вы хотите изменить этот возвращаемый объект, просто выполните return $http.get().then(someFunctionThatModifiesIt) Что someFunctionThatModifiesIt() сделает с вашими данными, если вы их вернете, они будут возвращены вызывающей стороне. Вы можете связать столько промисов, сколько хотите, прежде чем вернуть их из службы для предварительной обработки ваших данных. - person ste2425; 21.10.2015
comment
@Spikee, извините за двойной комментарий, но мне нужно было это сказать. Возврат обещания в вашем пользовательском разрешении во втором примере только для того, чтобы ваш вызывающий абонент знал, возникла ли ошибка, это очень плохо. Используйте .catch() в своей службе. Если ошибка не может быть устранена, верните $q.reject(error). Затем будут вызваны ваши абоненты .catch(). Вместо .then(function (p) { p.catch(); }); вы просто делаете .then().catch(); - person ste2425; 21.10.2015