0

I am having difficulties with Javascript's asynchronous functions. Code displayed below is so far almost entire code I have and I can't get it to work.

I ma trying to use Eventful API to pull some data from the server, and display it in my frontend which is created by jQuery.

So, the problem is following: function search, which is calling function Eventful.prototype.searchanje always ends up with undefined value, while a few seconds later, function searchanje console logs actual/recieved data.

I am fairly new to jQuery, and I was wondering if there is any kind of "template" for handling these things, concretely for waiting until the function returns value and then proceeding with next operations. So far I have tried using deferred and promises, and read quite a lot tutorials and stackoverflow answers on similar subjects, but I can't get it to work properly. Or, if deferred and promises are the right way to go, could you show me the way it is supposed to be done?

Thanks in advance

'use strict';

function Eventful(_name) {
var name = _name;
var appKey = 'appKey';
var that = this;

return {
    getName: function() {
        return name;
    },
    getAppKey: function() {
        return appKey;
    },
    search: function() {
        that.searchanje(appKey).then(function(oData) {
            console.log('oData');
        });
    }
};
}

Eventful.prototype.searchanje = function(appKey) {
var oArgs = {
    app_key: appKey,
    q: 'sport',
    where: 'Zagreb',
    date: '2013061000-2015062000',
    page_size: 5,
    sort_order: 'popularity',
};

EVDB.API.call('/events/search', oArgs, function(oData) {
    console.log(oData);
    return oData();
});
};
  • 1
    possible duplicate of [How to return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – Matteo Tassinari Jun 08 '15 at 08:06

2 Answers2

0

On the line

EVDB.API.call('/events/search', oArgs, function(oData) {

you are passing a CALLBACK function. This function (the one that starts function(oData)) is not executed immediately. It is executed asynchronously, when the result of your API call is returned.

Try putting console.log() statements around your code, and watch the order they appear in the console. For example:

function Eventful(_name) {
    var name = _name;
    var appKey = 'appKey';
    var that = this;

    return {
        getName: function() {
            return name;
        },
        getAppKey: function() {
            return appKey;
        },
        search: function() {
            console.log('Search function called');
            that.searchanje(appKey).then(function(oData) {
                console.log('searchanje returned with data:');
                console.log('oData');
            });
        }
    };
}

Eventful.prototype.searchanje = function(appKey) { 
    console.log('function searchanje being called with appKey: ', appKey);
    var oArgs = {
        app_key: appKey,
        q: 'sport',
        where: 'Zagreb',
        date: '2013061000-2015062000',
        page_size: 5,
        sort_order: 'popularity',
    };

    console.log('Calling EVDB.API.call');
    EVDB.API.call('/events/search', oArgs, function(oData) {
        console.log('EVDB.API callback executing with data:');
        console.log(oData);
        return oData();
    });
    console.log('finished calling EVDB.API.call');
};
Alex McMillan
  • 17,096
  • 12
  • 55
  • 88
0

I wonder if a better way ahead might be to "promisify" EVDB.API.call().

(function(app_key) {
    var appKeyObj = { 'app_key': app_key },
    EVDB.API.callAsync = function(path, params) {
        return $.Deferred(function(dfrd) {
            EVDB.API.call(path, $.extend(appKeyObj, params), function(oData) {
                if (oData.error === "1") {
                    //translate oData.status and oData.description into a javascript Error object
                    // with standard .name and .message properties.
                    err = new Error(oData.description);
                    err.name = oData.status;
                    dfrd.reject(err);
                } else {
                    dfrd.resolve(oData);
                }
            });
        });
    });
})('myAppKey'); //hard-coded app key

Notes:

  • The global namespace is avoided by :
    • using a self-executing anonymous wrapper
    • extending the EVDB.API namespace.
  • The "Async" suffix for a promisified method has a precendent in bluebird
  • From the little I understand of EVDB.API, EVDB.API.call() does just about everything, hence the single method EVDB.API.callAsync(). If necessary, further async methods could be added to EVDB.API
  • You might choose to use a dedicated promise lib such as bluebird or when.js in place of jQuery, In addition to including the lib, mods to the above code would be minor.

Now, instead of calling EVDB.API.call(path, params, callback) you would call EVDB.API.callAsync(path, params) to be returned a Promise.

var params = {
    //app_key will be inserted automatically
    q: 'sport',
    where: 'Zagreb',
    date: '2013061000-2015062000',
    page_size: 5,
    sort_order: 'popularity'
};
EVDB.API.callAsync('/events/search', params).then(function(oData) {
    console.log(oData);
}, function(err) {
    console.error(err);
});
Roamer-1888
  • 19,138
  • 5
  • 33
  • 44