Javascript OOP class - assigning property to function - javascript

Perhaps this has already been addressed, but couldn't find a suitable answer here. Apologies if it's the case. Here's the issue :
function Aclass(){
this.value1 = "a first value"
this.value2 = pulldata()
function pulldata(){
$.getJSON("data.json",function(data){
return data
})
}
}
var obj = new Aclass()
console.log(obj.value1)
console.log(obj.value2)
Result : "a first value" then "undefined"
The data var isn't available out of the pulldata's scope, and I'm not sure what's the best way around this.

Your pullData() function doesn't actually return anything explicitly, so its return is undefined - which means what you are seeing when you log obj.value2 is correct (though undesired).
Inside pullData() you are calling $.getJSON() and passing it an anonymous function as a callback, and it is that anonymous function that returns data but the return doesn't go anywhere because the ajax call is asynchronous and the callback doesn't occur until later.
You could try this:
function Aclass(classInitialisedCallback){
var self = this;
this.value1 = "a first value";
this.value2 = "not available yet";
$.getJSON("data.json",function(data){
self.value2 = data;
if (typeof classInitialisedCallback === "function")
classInitialisedCallback(self);
});
}
var obj = new Aclass(function(newInstance) {
// can use obj or newInstance to refer to the object
console.log(obj.value1);
console.log(newInstance.value2);
});
That is, set up your Aclass() constructor to take a parameter that is a callback function to be executed when the class is ready, i.e., after the result from $.getJSON() is available.

$.getJSON makes an asynchronous ajax call to your "data.json" URL. The second argument you've given it is the callback, which is called when the ajax call is finished.
Your pulldata function, however, just runs through without waiting for the answer and, thus, returns undefined.
It's not possible to do exactly what you're trying to do with asynchronous calls (and you should never use synchronous calls).
You'll have to rewrite your code to do your stuff in the callback instead. The callback is your "function(data){}" argument.
If the function you called wasn't asynchronous however, this is how the JS scope works and should've solved your problem:
function Aclass() {
var that = this;
this.value2 = 'not set';
var pullData = function() {
someCallToSomethingWithACallback(function() {
that.value2 = 'set';
}
}
}

Related

using a thunk to factor time out of async code

Kyle Simpson has an amazing class on pluralsight.
In one of the modules, he goes through a snippet of code that can be safely called asynchronously, and be certain that the results are going to be shown to the user in the same sequence with which the code was executed.
The function in its glory:
function getFile(file) {
var text, fn;
fakeAjax(file, function(response){
if (fn) fn(response);
else text = response;
});
return function(cb) {
if (text) cb(text);
else fn = cb;
}
}
We can call it like so:
I'm having a tough time understanding the getFile function:
where is cb defined? how does it get called, i.e. cb(text) if it's not defined anywhere?
when we call getFile, how does the response get a value at all?
getFile returns an anonymous function:
return function(cb) {
if (text) cb(text);
else fn = cb;
}
so var th1 = getFile("file") ends up assigning that anonymous function to the value of th1, so th1 can now be called with an argument - which becomes cb. So when later, we call th1 with:
th1(function(text1) {
...
we are passing in a second anonymous function (with argument text1) which is assigned to cb (shorthand for 'callback').
The reason it works is that when the ajax is complete, it does one of two things:
if fn is defined, calls fn with the response
if not, it stores the response
Conversely, when the returned anonymous function is called, it does one of two things:
if text is defined (i.e. a result is already received) then it calls the callback with the response
if not, it assigns the callback (cb) to fn
This way, whichever happens first - ajax complete, or thunk called, the state is preserved, and then whichever happens second, the outcome is executed.
In this way, the 'thunks' can be chained to ensure that while the ajax functions happen in parallel the output methods are only called in the sequence in which the fn values are assigned.
I think part of the confusion is unclear variable naming, and the use of liberal anonymous functions with out giving them an intention revealing name. The following should be functionally equivalent with clearer naming (I think):
function getFile(file) {
var _response, _callback;
fakeAjax(file, function(response){
if (_callback) _callback(response);
else _response = response;
});
var onComplete = function(callback) {
if (_response) callback(_response);
else _callback = callback;
}
return onComplete;
}
then:
var onFile1Complete = getFile("file1");
var onFile2Complete = getFile("file2");
var onFile3Complete = getFile("file3");
var file3Completed = function(file3Response) {
output("file3Response");
output("Complete!");
}
var file2Completed = function(file2Response) {
output(file2Response);
onfile3Complete(file3Completed)
}
var file1Completed = function(file1Response) {
output(file1Response);
onFile2Complete(file2Completed);
}
onFile1Complete(file1Completed);

Retrieve data from indexedDB and return value to function calling

I have share variable between javascript function which is asynchronous. One of them is main thread and another is event based. I want to return value when event is completed.
This is the code:
completeExecution = false; // Shared Variable (Global Variable)
indexDBdata = {}; // Shared Variable (Global Variable)
function getPermission(key) {
var permission_data={};
if(exist_in_local) {
indexdbConnection.getRecordByKey('userPermission',permitKey,function(data){
indexDBdata=data; // Before its complete function return value
});
} else {
// make ajax call & its working fine
}
return permission_data;
}
//get Data from IndexedDB
getRecordByKey:function(tableName,key,readRecords){
if(isEmptyOrNull(readRecords)){
console.log("callback function should not be empty");
return;
}
if(isEmptyOrNull(tableName)){
console.log("table name should not be empty");
return;
}
var returnObj={};
var isSuccessfull=false;
if(this.dbObject.objectStoreNames.contains(tableName)){
var transaction=this.dbObject.transaction(tableName);
var objectStore = transaction.objectStore(tableName);
objectStore.get(key).onsuccess = function(event) {
returnObj=event.target.result;
};
**//Return object after this events compelte**
transaction.oncomplete = function(evt) {
completeExecution=true;
indexDBdata=returnObj;
readRecords(returnObj);
};
transaction.onerror = function(evt) {
completeExecution=true;
indexDBdata={status:'404'};
readRecords("Table Not found");
};
} else {
completeExecution=true;
indexDBdata={status:'404'};
readRecords("Table Not found");
}
}
Problem is while retrieving data from indexedDB it always returns {} (empty object). I want to synchronised event thread and main thread or wait for event to be completed. I don't want to directly manipulate DOM on callbacks I have to return value.
If you have solution to above problem or any other trick then please help me.
Thanks in advance.
I don't find the question very clear, but if I understand it, then you need to learn more about writing asynchronous javascript. In general, functions that call callback functions are void (they return an undefined value). If you want to use the results of two callback functions together, then you will want to chain them so that upon the completion of the first function, which calls its callback function, the callback function then calls the second function which then calls the second callback. So there are four function calls involved. You will want to place the processing logic within the context of the successive callback function, instead of continuing the logic outside of the function and trying to use its return value.
In other words, instead of trying to do this:
function a() {}
function b() {}
var aresult = a();
var bresult = b(aresult);
// processing of both a and b
You would want to try and do something like following:
function a(acallback) {
acallback(...);
}
function b(bcallback) {
bcallback(...);
}
a(function(...) {
b(function(...) {
// all processing of both a and b
});
});

JavaScript - override a function with a function that contains async callbacks and still return original value

In JavaScript I want to override a function on an object, but still call the original function and return it's value. So I'd normally do something like this:
var render = res.render;
res.render = function() {
doSomethingNew();
return render.apply(this, arguments);
};
However, what if that override contains async callbacks that need to be fired first before calling the original function eg:
var render = res.render;
res.render = function() {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
return callNextMiddleware(middlewares, function() {
return render.apply(self, args);
});
};
function callNextMiddleware(middlewares, callback) {
var middlewareFunc = middlewares.shift();
if (middlewareFunc) {
return middlewareFunc.call(function() {
return callNextMiddleware(middlewares, callback);
});
}
else {
return callback();
}
}
Notice that I'm using a 'return' statement where required. I have one problem though, the 'middlewares' variable is an array of functions, each middleware function looks like this:
function myMiddleware(next) {
performLongRunningAsyncDataAccess(function() {
next();
});
}
Because it doesn't use 'return next()' the return value of the original res.render method is never passed back. I can get this to work if I get all the middleware functions to use 'return next()', but they come from an external source so I have no control over them, I can only guarantee that they will call 'next()'.
A bit of background, this is a Node.js app. The middleware is basically Connect middleware, and I'm trying to override the Express.js res.render method.
Generally it is a bad idea to mix asynchronous functions with return statements. Everything that you want to return, you can pass as arguments to your callback functions. So I still hope I understand your code correctly but I would assume, that you call the render function, which then grabs an array of middleware functions. Then you want to execute all the functions in that array, using the next as an callback to the previous. After all the functions have been executed, the render function should be called again, thus creating kind of an infinite loop. Assuming all of that, lets take a look at some of your return statements:
return middlewareFunc.call(function() {
return callNextMiddleware(middlewares, callback);
});
The first return in this block is useless since middlewareFunc is asynchronous and will therefore most likely return undefined. The second return statement is also useless, since it returns from the function, that you use as callback. But since your callback is just called by using next();, the return value will never be used.
else {
return callback();
}
In this block callback is the render function. So lets take a look at this function:
res.render = function() {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
return callNextMiddleware(middlewares, function() {
return render.apply(self, args);
});
};
So all last three return statements are essentially there, because you want to return something from your render function. But to be consistent, you should consider using a callback for that function as well:
res.render = function(callback) {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
callNextMiddleware(middlewares, function() {
//this will be called after all the middleware function have been executed
callback();
render.apply(self, args);
});
};
So basically you are getting rid of all the return statements and using pure asynchronous design patterns.
callNextMiddleware should return its recursive call's return value, not middlewareFunc's.
if (middlewareFunc) {
var result;
middlewareFunc.call(this, function() {
result = callNextMiddleware(middlewares, callback);
});
return result;
}
Fiddle: http://jsfiddle.net/mWGXs

Object in object

var UsersMenu = function(){
this.returnUsers = [];
this.retrieve = function(posts){
var temp = [];
$.post("router.php", { "action": "getUsersMenu", "posts" : posts},
function(data)
{
if(data.response){
for(var i=0; i<data.returnUsers.length; i++){
temp.push(data.returnUsers[i]);
}
this.returnUsers = temp; // i know what 'this' is incorrect
}
}, "json");
alert(this.returnUsers);
}
}
2 questions:
1. How to access to parent 'this' from jq object (returnUsers) ?
2. Why alert after jq post is calling before some alert in jq post ?
1 How to access to parent 'this' from jq object (returnUsers) ?
You could capture it in a closure:
var UsersMenu = function() {
this.returnUsers = [];
var self = this;
this.retrieve = function(posts) {
var temp = [];
$.post("router.php", { "action": "getUsersMenu", "posts" : posts },
function(data) {
if(data.response) {
for(var i = 0; i < data.returnUsers.length; i++) {
temp.push(data.returnUsers[i]);
}
self.returnUsers = temp;
}
}, "json");
}
};
2 Why alert after jq post is calling before some alert in jq post ?
Because AJAX is asynchronous. The $.post method which sends an AJAX request returns immediately but the success callback handler is executed much later, when a response is received from the server. So you shouldn't be putting the alert outside of this success handler. If you want to consume the results of an AJAX call this should happen only inside the callback which is when the result is available.
How to access to parent 'this' from jq object (returnUsers) ?
You should put the parent 'this' in a local variable like var self = this; outside the callback function, and then use self.returnUsers = temp;.
Why alert after jq post is calling before some alert in jq post ?
Because ajax works asynchronously, however for jQuery.ajax method, you can set it to work synchronously by async: false.
To answer your second question first: The $.post() function begins an asynchronous Ajax request. This means that the $.post() function itself returns immediately and execution continues with the next line of code which in this case is an alert(). Then once the Ajax request completes the anonymous function you provided to $.post() as a callback will be executed so if that function contain an alert() too it would be displayed then.
As to your first question: the value of this in a function depends on how a function was called, and jQuery typically sets it when it calls your callback functions but of course it won't be setting it to your UserMenu object. The easiest workaround is to save this in a variable that is local to your retrieve() function and then reference that variable from your callback:
var UsersMenu = function(){
this.returnUsers = [];
this.retrieve = function(posts){
var self = this,
temp = [];
$.post("router.php", { "action": "getUsersMenu", "posts" : posts},
function(data)
{
if(data.response){
for(var i=0; i<data.returnUsers.length; i++){
temp.push(data.returnUsers[i]);
}
self.returnUsers = temp;
}
}, "json");
alert(this.returnUsers);
}
}
Even though the retrieve() function will have finished by the time the Ajax callback is run the magic of JavaScript closures means that the inner anonymous function still has access to those local variables.
1 - Use a variable like that like
var that = this.returnUsers;
then inside the jq funciton you can refer to it like:
if(data.response){
for(var i=0; i<data.returnUsers.length; i++){
temp.push(data.returnUsers[i]);
}
that = temp; // Now 'this' is correct
}
2 - This becouse ajax calls are by default Asynchronous, means that javascript interpreter won't wait for the ajax call to be completed and it will continue executing the following statements, so put the alert in a callback function.
I can answer your second question.
Why alert after jq post is calling before some alert in jq post ?
Because AJAX is asynchronous, meaning you fire an AJAX request and don't wait for the outcome. You just register a callback function and carry on with the rest of the code. This "rest of the code" in your case is the alert statement.
It is highly unlikely (if not impossible) impossible for your AJAX response to arrive before the control reaches the alert statement.

How to get value returned by Callback function?

Here is my piece of code am trying:
initData:function(period)
{
this.getLoadObject('0',url, this.callbackFunction);
},
I want to receive a return value from callBackFunction, which I want to be returned by initData.
Can any body help me, am not so proficient with JS.
I tried similar question but didn't get help.
Actually, the callback function may very well be called asynchronously, that is after the return from the call to initData.
If it is synchronous however, you can do this:
initData:function(period)
{
var that = this;
var result;
this.getLoadObject('0',url, function() {
result = that.callbackFunction(arguments));
});
return result;
},
Although it's impossible to tell from your code snippet, it looks like your callback function will be called asynchronously. if this is the case you will need to set variables that you want to be populated by initData within the callback function itself.
you could also wrap the callback function:
var context = this;
this.getLoadObject('0',url, function() {
var returnedval = context.callbackFunction.apply(context,arguments);
context.SomeFuctionToUseValue(returnedval);
});
I think you could use variable outside the function, so you can access it inside the callback function and outside.
var result = false;
initData:function(period)
{
this.getLoadObject('0',url, this.callbackFunction);
//inside the callback you can modify the "result" then
return result;
},

Categories

Resources