I am trying to call a function to get a value from a 'subproduct' table and insert it in to another table. However the value which I am returning is not fetching the latest value from table and it is getting returned even before the snapshot part of the function is getting executed. I want it to run synchronously. Is there a better way in which it can be written.
function getGSTvalues(para1) {
var gstVar = 1;
var gstVarPromise = SubProductRef.once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
if (para1 == child.val().subproductName) {
gstvar = child.val().gst;
console.log("InsidePromise" + gstVar);
}
});
console.log("outside fun : " + gstVar);
});
console.log("outside fun1 : " + gstVar);
return gstVar;
};
This is where I am calling the above function:
var gstans = getGSTvalues($('#edit_ProductSubType').val());
Any help would be appreciated
Using synchronous logic would be a big step backwards. The best solution here would be to use the asynchronous pattern correctly and provide a callback function to getGSTvalues() which is executed after the async operation completes and receives the result as an argument. Try this:
function getGSTvalues(para1, cb) {
var gstVar = 1;
var gstVarPromise = SubProductRef.once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
if (para1 == child.val().subproductName) {
gstVar = child.val().gst;
}
});
cb && cb(gstVar);
});
};
getGSTvalues($('#edit_ProductSubType').val(), function(gst) {
console.log(gst);
// work with the value here...
});
Another alternative would be to return the promise from SubProductRef from getGSTvalues() and apply then() on that in the calling scope, although this would render the function largely redundant.
Also note that JS is case sensitive so gstVar is not the same as gstvar. I corrected this above.
I have an array of functions, as in:
funcArray = [func1, func2, func3];
When in a given function, I want to execute the next function in the array. How do I do this? Here is my basic skeleton:
function func1() {
// I get current function caller
var currentFunc = func1.caller;
// I want to execute the next function. Happens to be func2 in the example.
}
I cannot use indexOf function, as one would for an array of strings or numbers.
NOTE: This question appears to be similar to this and the one it refers to. However, it is a different question.
I want to alter the sequence of processing by merely modifying the array. That's the goal. A possibly more efficient approach would be appreciated.
Clarification: Based upon some of the comments:
funcArray is global.
The goal is to implement middleware for a Node.js HTTP module in as simple and efficient a manner as possible without using any third-party modules.
Unless func1 closes over funcArray, you cannot have it reach out and find func2 and execute it, nor should you. Even if func1 does close over funcArray, it would be poor separation of concerns for func1 to reach out and find itself in funcArray and then execute func2.
Instead, have other code that's in charge of running the functions.
If they're synchronous
If the functions complete their work synchronously, then it's simply:
funcArray.forEach(fn => fn());
or
for (const fn of funcArray) {
fn();
}
or if the result of one function should be passed to the next, you can use reduce:
const finalResult = funcArray.reduce((previousResult, fn) => fn(previousResult), undefined);
...where undefined is the value to pass to func1.
If they're asynchronous
If they don't do their work synchronously, you'll need to provide them a way to notify their caller that they've completed their work. Promises are a good, standard way to do that, but you could use simple callbacks instead.
If you make them return promises, for instance, you can use the old promise reduce trick:
funcArray.reduce((p, fn) => {
return p.then(() => {
fn();
});
}, Promise.resolve());
or if the result of one function should be passed to the next:
funcArray.reduce((p, fn) => {
return p.then(fn);
}, Promise.resolve());
You can provide an argument to Promise.resolve to set the value to pass to func1 (without one, it'll receive undefined).
You can bind to the function the index where it is in the array so you can use this index to get and call the next function:
var funcArray = [func1, func2];
var boundFuncArray = funcArray.map((f, i) => f.bind(null, i));
boundFuncArray[0]();
function func1(nextFunctionIndex) {
console.log('func1 called');
// Execute next function:
var nextFunc = boundFuncArray[nextFunctionIndex + 1];
nextFunc && nextFunc();
}
function func2(nextFunctionIndex) {
console.log('func2 called');
// Execute next function:
var nextFunc = boundFuncArray[nextFunctionIndex + 1];
nextFunc && nextFunc();
}
As T.J Crowder stated in the comment below, you can also bind the next function to the current one:
var funcArray = [func1, func2];
var boundFuncArray= funcArray.map((f, i, arr) => f.bind(null, arr[i + 1]));
boundFuncArray[0]();
function func1(nextFunc) {
console.log('func1 called');
// Execute next function:
nextFunc && nextFunc();
}
function func2(nextFunc ) {
console.log('func2 called');
// Execute next function:
nextFunc && nextFunc();
}
You can get the current function's name with arguments.callee.name, loop through the array of functions, and call the next function:
funcArray = [func1, func2, func3];
// Only func1() and func2() will be documented since the others have repeating code
function func1() {
// show the current function name
console.log(arguments.callee.name);
// loop the array of functions
for(var i = 0; i < funcArray.length; ++i)
{
// when the current array item is our current function name and
// another function exists after this then call it and break
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
function func2() {
console.log(arguments.callee.name);
// some logic which switches our next function to be func4()
funcArray[2] = func4;
for(var i = 0; i < funcArray.length; ++i)
{
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
function func3() {
console.log(arguments.callee.name);
for(var i = 0; i < funcArray.length; ++i)
{
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
function func4() {
console.log(arguments.callee.name);
for(var i = 0; i < funcArray.length; ++i)
{
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
// call the first function
funcArray[0]();
Output:
func1
func2
func4
I have solved it this way:
// Adding next options to array
function addNext(array) {
array.last = 1
Object.defineProperty(array, 'next', {get:
function() {
if(this.last < this.length) {
this.last++
return this[this.last-1]
} else {
this.last = 1
return () => {}
}
}
});
}
// The functions for array (has to be function and not arrow function)
function first(param) {
console.log('first',param)
return this.next(param)
}
function second(param) {
console.log('second',param)
return this.next(param)
}
function third(param) {
console.log('third',param)
return this.next(param)
}
// The array
let fns = [first,second,third]
// Adding next option to array
addNext(fns)
// Run first function from array
fns[0]('test')
I dont know if your functions require certain parameters but this is the first thing that came to my mind.
var functArray = [
function() {
console.log("function1 executed");
},
function() {
console.log("function2 executed");
},
function() {
console.log("function3 executed");
},
function() {
console.log("function4 executed");
}];
functArray.forEach(function(x){
x();
});
The accepted answer and other comments did help me, but the way I implemented it is as follows:
//The functions are defined as variables.
//They do not get hoisted, so must be defined first.
func1 = function (arg1, arg2) {
//Code to do whatever...
...
//Execute the next function.
//The name of the function is returned by executing nextFunc()
global[nextFunc()](arg1, arg2, arg3);
}
func2 = function (arg1) { //Note different type of args
...
}
//Note that this is an array of strings representing function names.
funcArray = ["func1", "func2", "func3",...]
//Start the execution...
func1(arg1, arg2);
function nextFunc() {
var currentFuncName = nextFunc.caller.name;
var index = funcArray.indexOf(currentFuncName);
if (index < funcArray.length)
return funcArray[index+1];
}
The sequence of functions to be executed is easily managed through the array funcArray. The number or type of arguments is not fixed for each function. Additionally, the functions control if they should stop the chain or continue with the next function.
It is very simple to understand requiring basic Javascript skills. No overheads of using Promises.
"global" gets replaced by "window" for browser. This is a Node.js implementation. The use of function names in the array will, however, break if you minify the JS code. As I am going to use it on the server, I do not expect to minify it.
You can do it in this way with promise.all if your functions to be executed in parallel.
let toBeExecutedList = [];
toBeExecutedList.push(() => this.addTwoNumber(2, 3));
toBeExecutedList.push(()=>this.square(2));
And Then wherever you want to use them, do it like this:
const resultArr = await Promise.all([
toBeExecutedList.map(func => func()),
]);
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.
I am new to Javascript and call back functions. is this the correct way to do a call back? when i test i get an infinite loop. I want to retrieve from the database and store in an object's variable to use in getSport().
constructor(matchid) {
this.hasLoaded = false;
this.matchid = mid;
this.Match = {
"sport": "baskt",
"winner": -1,
};
}
rload(callback) {
this.hasLoaded = true;
matchDataBaseRef.child(this.mid)
.on("value", function (snapshot) {
this.Match = snapshot.val();
callback();
});
}
get getSport() {
if (!this.hasLoaded) {
this.rload(this.getSport);
}
return this.Match['sport'];
}
That's not the right approach. You are trying to synchronize in this.getSport. Instead, you should have your initialization inside the callback and do not infinitely call it. Let's suppose you have something like this:
function myTask(params) {
//do something
params.callback();
//do something
}
then you should not work with that like this unless you have a very good reason:
var foo = function() {
myTask({callback: foo});
};
Instead of it, in most cases you need something like this:
var foo = function(cb) {
myTask({callback: cb});
};
cb needs to be defined though separately. So do not pass the wrapper function as a callback if that is not precisely what you want to do.
I need to run a function on my node.js server, that completes the same task every 15 minutes.
I Used for that setInterval as in example number 3 here - http://tinyurl.com/c2jj7dl.
So, I got to something like this:
exports.start = function (list, callback){
setInterval(stuffTop.loadstuff, 900000, list, function (parsedList) {
// CODE STUFF HERE
// THEN THE CALLBACK.
callback(parsedDynamicList);
});
}
Actually this stuff work, but the function gets completed for the first time - only after 900000MS.
Is there an option to make to function complete (in the first round) - straight when called ? Thanks.
Use a function which recursivly calls itself:
foo = function(){
doStuff()
setTimeout(foo,900000)
}
In your case It would look like this:
exports.start = function (list, callback){
var foo = function () {
stuffTop.loadstuff(list, function(parsedList) {
//CODE STUFF HERE
//THEN THE CALLBACK
callback(parsedDynamicList);
setTimeout(foo,900000);
});
}
foo();
}
The solution to your question is simple. Call the function before going into the setInterval. Like this:
var callback=function(){}
var list=['some','list'];
var repeaterFunction = function(){console.log("do now!")}
var start = function (list, callback){
repeaterFunction();
var repeater = setInterval(repeaterFunction, 5000, list, function(parsedList){
// CODE STUFF HERE
// THEN THE CALLBACK.
callback(parsedDynamicList);
});
}
start()
The fact that I use var repeater = setInterval(... allows for the clearInterval(repeater) whenever you wish.
Here's the fiddle