връщане на булево след като обещанието е разрешено/отхвърлено?

Имам функция, която работи абсолютно добре. Просто искам да върна 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 винаги е недефиниран. Защо функцията не може да върне проста булева стойност?

Актуализация:

Ето какво се опитвам да направя: просто искам да отворя изскачащ прозорец, който уведомява потребителя, че е офлайн. Извиквам функцията 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

Promise работи по различен начин с прости изрази, защото те може да се върнат по-късно, така че може да се наложи да преосмислите потока на вашата програма, за да се справите с различни начални и крайни състояния.

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
не Случаят, в който наистина трябва да създадете отложено, е когато ядрото на функцията не връща обещание, като $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