kalabo
kalabo

Reputation: 564

jQuery Deferred promise logic assistance

I am trying to figure out the logic required for promises to work. My (simplified) example does this:

var FLEX = FLEX || {};
FLEX.Core = {
__networkIdToken: '',
__r: "",
Init: function() {          
    var deferred = $.Deferred();        
    FLEX.Core.Config();
    FLEX.Core.RegisterHandlers();
    FLEX.Core.Execute();    
},

Config: function() {
    yam.config({
        debug: true,
        appId: FLEX_YAMMER_CONFIGID
    }); 
},

RegisterHandlers: function() {
    $(FLEX_YAMMER_LOGINBUTTON).on('click', function(){
        FLEX.Core.Login();
    });
},

Execute: function() {
    //Get Network Token from local storage (if exists)
    __networkIdToken = localStorage.getItem(FLEX_YAMMER_AUTHTOKEN);
    if(__networkIdToken != null)
    {       
        //If network token is set then set Auth Token and continue
        yam.platform.setAuthToken(__networkIdToken);    

        //RETURN NEEDS TO HAPPEN HERE

    }
    else
    {
        //If no Network Token set, display login panel to enable login
        FLEX.Core.ShowLoginPanel(false);
    }   
},

ShowLoginPanel: function (_loggedIn) {
    if (_loggedIn) {
        $(FLEX_YAMMER_LOGINPANEL).hide();
    } else {
        $(FLEX_YAMMER_LOGINPANEL).show();
    }   
}
}


$(document).ready(function () {
    FLEX.Core.Init().done(testFunction);
    function testFunction()
    {
        alert('Test');
    }
});

The Call from document ready needs to check if the user is logged in. (execute function). If the local storage object (which sets __networkIdToken) is empty then it will show the login panel and this has independent button logic (removed from example). If there IS a network id then i would like a promise to be returned here...removed the need to any async logic for login.

Thanks

Upvotes: 0

Views: 184

Answers (1)

Bergi
Bergi

Reputation: 665536

    __r = $.Deferred();
    […]
    return __r;

__r is a property of your object, but here you're assigning to a global variable! Change to

    this.__r = …
    […]
    return this.__r;
    FLEX.Login();
}

You're not returning anything from the INIT method on which the .done() could be called. (Also, you're missing .Core in the access of .Login) Change it to

    return this.Login();
}

Design Pattern improvement: Every function that does any asynchronous tasks should create an Deferred itself, and return a Promise for it.

with a final function which i was hoping to return the deferred object

No, that's not how promises work. The initial function handles the deferred and returns the promise, the "final" (asynchronous callback) function only resolves the deferred - which might trigger other processes (the "final" is local to one async task, not "final" handler in a chain of tasks).

var FLEX = FLEX || {};
FLEX.Core = {
    __networkIdToken: '',
    __r: null,
    Init: function() {
        // some pseudo-action that might resemble your process
        // implemented with promises
        this.__r = FLEX.getAuthToken().catch(function(noAuthTokenError) {
            showLoginForm();
            return getNextFormSubmission().then(function(credentials) {
                return serverRequest(credentials).then(function (token) {
                    hideLoginForm();
                    return token;
                }, function(authError) {
                    // try again? Get next form submission...
                });
            });
        }).then(function(token) {
            yam.platform.setAuthToken(token);
        });
        return this.__r;
    },
    Login: function () {
        var d = $.Deferred();
        //Asynchronous Login Code Goes here, callback {
            d.resolve();
            // or
            d.reject();
        // }
        return d.promise();
    }
    // similarly for the other async tasks
}

If there IS a network id then i would like a promise to be returned here...removed the need to any async logic for login

You always want to return a promise, even if the result is synchronously available. The logic to handle a maybe-async login must be asynchronous anyway. In your case, it might look like

FLEX.getAuthToken /* as used above */ = function() {
    var __networkIdToken = localStorage.getItem(FLEX_YAMMER_AUTHTOKEN);
    if (__networkIdToken != null)
        return $.when(__networkIdToken);
    else
        return $.Deferred().reject(); // the rejection will be handled by the .catch
        // or maybe try another storage?
}

Upvotes: 1

Related Questions