How to excute a function only once for same argument - javascript

My function call is given below:
await insertingMatchIdsInAllTeamPlayers(fieldersA, matchID)
Suppose the function is called with matchID '1', it should get executed, but if the function is called again with matchId '1'(It will in my case), it should not be executed. However, if it is called with id '2' (basically id !== '1'), it should be executed. I don't care for fieldersA argument.

You could track all passed arguments in array outside of the function. When you call the function, it will check, if the supplied argument is in the array. If it's not, call the function and insert the argument into the array. If the argument is already in the array, don't call the function.
const suppliedMatchIDs = [];
function insertingMatchIdsInAllTeamPlayers(fieldersA, matchID) {
if (suppliedMatchIDs.includes(matchID)) {
return;
} else {
suppliedMatchIDs.push(matchID);
}
// Your function here
}
The general concept of caching arguments to speed up function calls is called memoization.

const matchIdFirstTimeOne = true
if(matchId === 1 && matchIdFirstTimeOne) {
await insertingMatchIdsInAllTeamPlayers(fieldersA, matchID);
matchIFirstTimeOne = false
}

Using closure could solve it.
var insertingMatchIdsInAllTeamPlayers = (function() {
var executed = [];
return function(fieldersA,val) {
if (executed.indexOf(val) == -1) {
executed.push(val);
console.log(val);
}
};
})();
insertingMatchIdsInAllTeamPlayers('',1); // console.log(1)
insertingMatchIdsInAllTeamPlayers('',1); //
insertingMatchIdsInAllTeamPlayers('',2); // console.log(2)
insertingMatchIdsInAllTeamPlayers('',2); //
insertingMatchIdsInAllTeamPlayers('',3); // console.log(3)

Related

How is the timeoutID accessible before initialization?

function addNew() {
let id = setTimeout( function() {console.log(id)}, 0)
}
addNew()
How is id able to be accessed before initialization? I think this is no different from the second code snippet.
function customTimeout(fn) {
fn()
return 32423
}
function addNew() {
let id = customTimeout( function() {console.log(id)})
}
addNew()
Variables which have not initialized yet cannot be directly referenced by a line that runs until the variable gets initialized (the let id = line), but it's still permitted for functions which have not been called yet to reference the variables inside.
In the first snippet, the setTimeout callback does not run until the let id = line has finished initializing the id variable, so it's permitted.
In the second snippet, the callback passed to customTimeout is running before the let id = line in addNew has finished initializing id, so it's not permitted.
// Permitted:
const fn = () => {
// do something with someVariable
console.log(someVariable);
};
// The above is fine
let someVariable = 'foo';
// just make sure fn is called ONLY AFTER `let someVariable;` runs
fn();
// Not permitted:
const fn = () => {
console.log(someVariable);
};
fn();
let someVariable = 'foo';
// Permitted, since fn is called asynchronously:
function customTimeout(fn) {
Promise.resolve().then(fn);
return 32423
}
function addNew() {
let id = customTimeout( function() {console.log(id)})
}
addNew()
// Permitted, since fn is called asynchronously:
function customTimeout(fn) {
setTimeout(fn);
return 32423
}
function addNew() {
let id = customTimeout( function() {console.log(id)})
}
addNew()
// Permitted, since fn is called after `id` has finished being assigned to:
function customTimeout(fn) {
return [12345, fn];
}
function addNew() {
let [id, fn] = customTimeout( function() {console.log(id)})
fn();
}
addNew()
See example, hope you understand.
function addNew() {
let id = setTimeout( // <-- 1
function() { // <-- 2
console.log(id) // <--- here
}
, 0)
}
addNew()
/*
* It will not work.
*/
function addOld() {
console.log(id)
let id = 2;
}
addOld()
When you call setTimeout (even with a timeout of 0), the callback doesn't run right away. It's placed into a stack to be ran at some point in the future.
So, in your 1st example, you are setting id to the "timeoutID" returned by setTimeout. When the callback is ran in the future (asynchronously), id is there and the callback can see it.
In your 2nd example, you are passing a callback to customTimeout. Before this function returns anything, the callback is ran. It's ran immediately (synchronously) and after the callback is ran, then customTimeout returns a value.
Since this value is returned after the function is ran, the function cannot see it.

How to set a default value for callback function?

Hello I'm learning about Javascript Callback Function, but I don't know how to set a default value to callback function.
let mul = (num1,num2) =>{
return num1*num2;
}
let cal = (num1,num2,cb) =>{
console.log(`The Answer is ${cb(num1,num2)}`)
}
cal(3,2,mul);
Here the code I tried to set a default value to callback function.
let sum = (num1,num2) =>{
return num1+num2;
}
let mul = (num1 = 3,num2 = 2) =>{
return num1*num2;
}
let cal = (num1,num2,cb) =>{
console.log(`The Answer is ${cb(num1,num2)}`)
}
cal(mul);
Instead of cal(numberone,numbertwo,mul);. Can I only call a function like this cal(mul);.
Edit
let testmul = (num1 = 3,num2 = 2) =>{
let result = num1*num2;
console.log(`${result}`);
}
testmul();
This is what I would like to do. If I doesn't put a number in function. The function will have a default value. But this time I want to try it with a Callback function.
The answers to your question read more: https://nodejs.org/en/knowledge/javascript-conventions/how-to-create-default-parameters-for-functions/
You have to check if the last parameter is undefined and then manually fix all the other parameters before continuing in the code. This case is also valid for modern JavaScript(ES6/ES2015). The example shows you how to do that:
const example = function (param1, optParam, callback) {
if (callback === undefined) {
// only two parameters were passed, so the callback is actually in `optParam`
callback = optParam;
//give `optParam` a default value
optParam = "and a default parameter";
}
callback(param1, optParam);
}
example("This is a necessary parameter", console.log);
example("This is a necessary parameter", "and an optional parameter", console.log);
let DefaultCallback = (args) => {
... do stuff
}
then you can do like this:
function myFunc(param1, param2, callback = DefaultCallback){
return param1;
callback();
}
then if you don't provide a callback like myFunc(2) as you said, it will have the default values of the function defaultCallback and it works for other variables as well, if you want to define default function parameters

JavaScript function: what does this do?

I have been looking at this code for sometime now, trying to understand what it does but I can't really get my head around it. I need help with understanding what this function actually does
function element(array, gen) {
if(gen === undefined) {
gen = fromTo(
0,
array.length
);
}
return function() {
var index = gen();
if(index !== undefined) {
return array[index];
}
};
}
function concat(...gens) {
var next = element(gens),
gen = next();
return function recur() {
var value = gen();
if(value === undefined) {
gen = next();
if(gen !== undefined) {
return recur();
}
}
return value;
};
}
element is not a javascript built-in which means it must be defined elsewhere. Without knowing its function, it is impossible to say exactly what is happening, but here is what I can tell you.
concat takes n arguments of the same type. Without knowing what element does I can't tell you what type that is, but it can take as many as you need to give it. That is what the spread operator ... is telling you.
It returns a function that takes 0 arguments. When called, it continues to call itself checking if the return value of gen() is defined, if it is not, it changes gen to be the return value of next() and calls gen() again. It repeats this process until the return value of gen() is defined, and then returns that value.
Using it would look something like this.
var recur = concat(a,b,c,d,e); // can take any number of arguments of the same type
var someValue = recur(); // calls itself until it has a value to return
console.log(someValue); // use the value

In JavaScript, how to execute next function from an array of functions

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()),
]);

Updating an array inside a call back

I have the following two functions:
var abc;
function updateNum() {
abc=0;
g.dbm.transaction("leagues").objectStore("leagues").openCursor(null, "prev").onsuccess = function (event) {
var teams, i;
team.filter({
attrs: ["tid", "abbrev", "region", "name", "cid"],
seasonAttrs: ["winp", "playoffRoundsWon"],
season: g.season
}, function (teams) {
// Sort teams by playoffs and winp, for first round
teams.sort(function (a, b) {
if (a.playoffRoundsWon < b.playoffRoundsWon) {
return -1;
}
if (a.playoffRoundsWon > b.playoffRoundsWon) {
return 1;
}
return a.winp - b.winp;
});
abc+=1;
});
};
}
function getNum() {
return abc;
}
What I am trying to do is update the variable abc inside the callback function and then return it. I do this by first calling the updateNum() function in another file. Then I assign a variable to the value of getNum()
Here is how a sample code would look like:
myFile.updateNum();
var number = myFile.getNum();
I am currently unable to return the updated value of num. number keeps returning 0 (the default value) instead of the newly updated value (which is 1).
How can I get it to show an updated value? Please let me know if I need to add any more information.
Well, if updateNum is async, it would have to take a callback as argument so that you can be notified when the number was updated.
E.g.
var num = 0;
function updateNumAsync(callback) {
setTimeout(function () {
num = 1;
callback && callback(num); //call the callback if provided
}, 500);
}
updateNumAsync(function (num) {
console.log(num); //updated num
});
Here is a general pattern for using an asynchronous function with a callback to pass the asynchronous results around. What is team.filter? You will need to design your code such that the asynchronous portion calls a callback() function that was passed to the enclosing function.
If filtering gives you problems you may want to look at https://github.com/caolan/async#filterarr-iterator-callback
(function main(){
getNum(function(err, abc){
console.log('thx for playing '+abc)
});
})();
function getNum(anotherCallback) {
// Whatever code relies on the result of an asynchronous function must be
// placed inside the callback function
countTeams(function(abc){
console.log('countTeams completed, abc='+abc);
var err = null;
anotherCallback(err, abc);
});
};
function countTeams(callback){
var abc=0;
g.dbm.transaction("leagues").objectStore("leagues").openCursor(null, "prev").onsuccess = function (event) {
var teams, i;
// I don't know what this filter function does, I am assuming it's synchronous
team.filter({
attrs: ["tid", "abbrev", "region", "name", "cid"],
seasonAttrs: ["winp", "playoffRoundsWon"],
season: g.season
}, function (teams) {
// Sort teams by playoffs and winp, for first round
teams.sort(function (a, b) {
if (a.playoffRoundsWon < b.playoffRoundsWon) {
return -1;
}
if (a.playoffRoundsWon > b.playoffRoundsWon) {
return 1;
}
return a.winp - b.winp;
});
abc+=1;
});
return callback(abc); // 0 or n depending on what team.filter does
};
};

Categories

Resources