This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 5 years ago.
I am trying to get value out of java script function to a variable
var isMember;
IsCurrentUserMemberOfGroup("Team Management System Members", function (isCurrentUserInGroup) {
if (isCurrentUserInGroup) {
//alert("Admin");
isMember = true;
return true;
}
else {
isMember = false;
//alert("NoAdmin")
}
});
alert(isMember);
the other function used to be called
function IsCurrentUserMemberOfGroup(groupName, OnComplete) {
var currentContext = new SP.ClientContext.get_current();
var currentWeb = currentContext.get_web();
var currentUser = currentContext.get_web().get_currentUser();
currentContext.load(currentUser);
var allGroups = currentWeb.get_siteGroups();
currentContext.load(allGroups);
var group = allGroups.getByName(groupName);
currentContext.load(group);
var groupUsers = group.get_users();
currentContext.load(groupUsers);
currentContext.executeQueryAsync(OnSuccess, OnFailure);
function OnSuccess(sender, args) {
var userInGroup = false;
var groupUserEnumerator = groupUsers.getEnumerator();
while (groupUserEnumerator.moveNext()) {
var groupUser = groupUserEnumerator.get_current();
if (groupUser.get_id() == currentUser.get_id()) {
userInGroup = true;
break;
}
}
OnComplete(userInGroup);
}
function OnFailure(sender, args) {
OnComplete(false);
}
}
but when I execute i am getting the value : undefined
thanks
You have to ensure that the function associated with IsCurrentUserMemberOfGroup gets invoked before you attempt to check the value of isMember. You can't just put an alert() after the function's code and expect that it will run the function first.
Here's a working example:
var isMember;
function checkUser(isCurrentUserInGroup) {
if (isCurrentUserInGroup) {
isMember = true;
} else {
isMember = false;
}
}
alert(isMember); // undefined because function hasn't bee called yet
checkUser(); // invoke the function with no data being passed in
alert(isMember); // false because undefined was passed into function
checkUser("Something"); // invoke the function with data being passed in
alert(isMember); // true because something was passed into function
most likely there's some asynchronous stuff going inside IsCurrentUserMemberOfGroup, the callback you're passing will be postponed as soon as your async stuff completes.
Potentially your IsCurrentUserMemberOfGroup function could look like this this:
function IsCurrentUserMemberOfGroup(someString, callback){
..
//async stuff here
myAPI.asyncMethod(callback);
//here the parser will go on with the synchronous code and park in the event queue the callback for the async method
..
}
as soon as the parser encounter the async function, the callback will be parked inside the event queue. the async function, (e.g. reading from file, deal with the network, etc.) will be handled by some other OS task that will notify the javascript thread when they finish, so that the callback could be finally invoked.
The problem is here.
the parser executes synchronously, line by line, so it must keep going to not block the ui, that's why it reach the alert function before the async stuff completes, and print undefined, because member is still not assigned.
Related
I don't know how to ask this on google that's why I asked here instead,
The console.log from the getListByElement() function won't execute here,
I am modifying a very large existing project and uses functionality hooks for validation purposes and executes that hook on certain .on events, what I want to know is why the console.log won't get executed,
which gets executed first,
Order of execution on my understanding
1. trigger event function for the field `fieldName`
2. fieldName.functionalityHook = [Apple.functionalityHook()];
3. Apple.functionalityHook = function(func) {
4. return function(e) {
5. getListByElement(ele); and display console.log();
6. return func;
Here is the sample code that I have,
var Apple= window.Apple; // global
fieldName.functionalityHook = [Apple.functionalityHook()];
Apple.functionalityHook = function(func) {
return function(e) {
var ele = $(e.target);
getListByElement(ele);
return func;
}
}
function getListByElement(ele){
console.log('ele here');
}
Thank You for answering,
as par my understanding your getListByElement() is not invoking because of the function initialization. You are calling the functionalityHook() before its initialization.
fieldName.functionalityHook = [Apple.functionalityHook()];
Apple.functionalityHook = function(func) {..........
and this invocation returning a function
return function(e) {
var ele = $(e.target);
getListByElement(ele);
return func;
}
and inside this function getListByElement() is calling.
So, the correct code arrangement should be like this.
var Apple= window.Apple;
function getListByElement(ele){
console.log('ele here');
}
Apple.functionalityHook = function(func) {
return function(e) {
var ele = $(e.target);
getListByElement(ele);
return func;
}
}
fieldName.functionalityHook = [Apple.functionalityHook()];
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);
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
});
});
Is there a possibility to make some delay? I call a function in a while loop. This function calls executeQueryAsync which has to finish before the loop continues. When I use an alert my code works but without it doesn't.
while (listPermsEnumerator.moveNext()) {
enumG = groups.getEnumerator();
var rAssignment = listPermsEnumerator.get_current();
var member = rAssignment.get_member();
var groupCounter = 1;
var name = '';
//alert(''); This alert makes code work
while (enumG.moveNext()) {
var group = enumG.get_current();
var groupname = group.get_title();
//alert(groupname);
if (member.get_title() === groupname) {
name = groupname;
SP.SOD.executeOrDelayUntilScriptLoaded(function(){
retrieveAllUsersInGroup(groupname, groupCounter, groups);
}, key);
}
groupCounter++;
}
roleAssignment = this.listRoleAssignments.getByPrincipalId(member.get_id());
roleBindings = roleAssignment.get_roleDefinitionBindings();
// in checkPermission() another executeQqueryAsync is called
checkPermission(context, roleAssignment, roleBindings, name);
}
...
function checkPermission(context, roleAssignment, roleBindings, name) {
this.name = name;
context.load(roleAssignment);
context.load(roleBindings);
context.executeQueryAsync(Function.createDelegate(this, Bind), Function.createDelegate(this, BindFail));
}
The simplest solution would be to code your methods in a way that reflects the purpose of asynchronous operations. You seem to be trying to work around the ExecuteQueryAsync and trying to "make" it synchronous.
Here is a similar example -- see the 2nd answer: ( https://sharepoint.stackexchange.com/questions/95907/executequeryasync-in-for-loop ) Basically you a) write the callback function inline, and b) you put the loop in the success callback.
(What's great about writing the "success" callback function in line is the success callback function then has access to all the variables in the method. It's a closure).
If you need to loop through an array of asynchronous jobs, you can do something like this:
var reports = [11, 12, 14, 15];
function doTheReport() {
if (reports.length === 0) {
alert('All reports are done now.');
return;
}
var report_Id = reports.pop();
$.ajax({
url: "/DoTheReport",
complete: function () {
doTheReport();
}
});
};
This question already has answers here:
Semaphore-like queue in javascript?
(4 answers)
Closed 6 years ago.
I have created a Queue class in javascript and I would like to store functions as data in a queue. That way I can build up requests (function calls) and respond to them when I need to (actually executing the function).
Is there any way to store a function as data, somewhat similar to
.setTimeout("doSomething()", 1000);
except it would be
functionQueue.enqueue(doSomething());
Where it would store doSomething() as data so when I retrieve the data from the queue, the function would be executed.
I'm guessing I would have to have doSomething() in quotes -> "doSomething()" and some how make it call the function using a string, anyone know how that could be done?
All functions are actually variables, so it's actually pretty easy to store all your functions in array (by referencing them without the ()):
// Create your functions, in a variety of manners...
// (The second method is preferable, but I show the first for reference.)
function fun1() { alert("Message 1"); };
var fun2 = function() { alert("Message 2"); };
// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);
// Remove and execute the first function on the queue
(funqueue.shift())();
This becomes a bit more complex if you want to pass parameters to your functions, but once you've setup the framework for doing this once it becomes easy every time thereafter. Essentially what you're going to do is create a wrapper function which, when invoked, fires off a predefined function with a particular context and parameter set:
// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
return function() {
fn.apply(context, params);
};
}
Now that we've got a utility function for wrapping, let's see how it's used to create future invocations of functions:
// Create my function to be wrapped
var sayStuff = function(str) {
alert(str);
}
// Wrap the function. Make sure that the params are an array.
var fun1 = wrapFunction(sayStuff, this, ["Hello, world!"]);
var fun2 = wrapFunction(sayStuff, this, ["Goodbye, cruel world!"]);
// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);
// Remove and execute all items in the array
while (funqueue.length > 0) {
(funqueue.shift())();
}
This code could be improved by allowing the wrapper to either use an array or a series of arguments (but doing so would muddle up the example I'm trying to make).
Canonical answer posted here
Here is a nice Queue class you can use without the use of timeouts:
var Queue = (function(){
function Queue() {};
Queue.prototype.running = false;
Queue.prototype.queue = [];
Queue.prototype.add_function = function(callback) {
var _this = this;
//add callback to the queue
this.queue.push(function(){
var finished = callback();
if(typeof finished === "undefined" || finished) {
// if callback returns `false`, then you have to
// call `next` somewhere in the callback
_this.next();
}
});
if(!this.running) {
// if nothing is running, then start the engines!
this.next();
}
return this; // for chaining fun!
}
Queue.prototype.next = function(){
this.running = false;
//get the first element off the queue
var shift = this.queue.shift();
if(shift) {
this.running = true;
shift();
}
}
return Queue;
})();
It can be used like so:
var queue = new Queue;
queue.add_function(function(){
//start running something
});
queue.add_function(function(){
//start running something 2
});
queue.add_function(function(){
//start running something 3
});
Refer to the function you're storing without the () at the end. doSomething is a variable (that happens to be a function); doSomething() is an instruction to execute the function.
Later on, when you're using the queue, you'll want something like (functionQueue.pop())() -- that is, execute functionQueue.pop, and then execute the return value of that call to pop.
You can also use the .call() method of a function object.
function doSomething() {
alert('doSomething');
}
var funcs = new Array();
funcs['doSomething'] = doSomething;
funcs['doSomething'].call();
In addition, you can also add the function directly to the queue:
funcs['somethingElse'] = function() {
alert('somethingElse');
};
funcs['somethingElse'].call();