Reputation: 832
In trying to find a way to run some functions that are stored in an array like the one below, I produced the following code.
This works fine, but sometimes it seems to execute a function before a previous one is finished.
How do I prevent functions being executed in the code below before previous are finished?
An example of an array with several function "calls" and parameters
["A3",[6]],["B1",["TEST",4,13]],["A10",[2]],["A7",[1,5]]
The for loop that executes each function call from above array
function routineConverter(v){
var routines = JSON.parse('[' + v + ']');
for ( var i=0; i < routines.length ; i++ ){
switch (routines[i][0]) {
case 'A1':
routines[i] = A1( routines[i][1] );
break;
case 'A2':
routines[i] = A2( routines[i][1] );
break;
case 'A3':
routines[i] = A3( routines[i][1] );
break;
case 'A4':
routines[i] = A4( routines[i][1] );
break;
case 'A5':
routines[i] = A5( routines[i][1] );
break;
case 'A6':
routines[i] = A6( routines[i][1] );
break;
case 'A7':
routines[i] = A7( routines[i][1] );
break;
case 'A8':
routines[i] = A8( routines[i][1] );
break;
case 'A9':
routines[i] = A9( routines[i][1] );
break;
case 'A10':
routines[i] = A10( routines[i][1] );
break;
case 'B1':
routines[i] = B1( routines[i][1] );
break;
case 'B2':
routines[i] = B2( routines[i][1] );
break;
case 'E':
routines[i] = conditionalAction( routines[i][1] );
break;
case 'X1':
//console.log(routines[i][1]);
routines[i] = REMOVE(routines[i][1] ); //B1( routines[i][1] );
break;
}
}
var a = [routines];
}
Example of a function:
function A1(p) {
$('#tbl tr td:nth-child(' + parseInt(p) + ')').after('<td></td>');
}
Upvotes: 1
Views: 197
Reputation: 3681
I am going to assume you are using asynchronous code. Synchronous code in your example would already work in the way you desire, with functions being called sequentially.
In order to make this work asynchronously you can take advantage of async/await
and promises. In doing so async
functions will be called, but your switch statement will wait until they have finished before allowing the thread to continue the loop. This can be seen in the example I have attached.
Note how C has the lowest timeout and would finish first if asynchronously called without using await. However due to using an async
function with await
C is the last function to be called.
var routines = [["A1",["PARAM-A"]],["B1",["PARAM-B"]],["C1",["PARAM-C"]]];
function A1(param) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`A1 FUNC: ${param}`);
}, 1000);
});
}
function B1(param) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`B1 FUNC: ${param}`);
}, 500);
});
}
function C1(param) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`C1 FUNC: ${param}`);
}, 100);
});
}
async function routineConverter(routines){
var results = []
for ( var i=0; i < routines.length ; i++ ) {
// waits for the promise to resolve
let returnedValue = await funcSwitch(routines, i)
console.log(returnedValue)
//assign value
results[i] = returnedValue;
}
//print out final results
console.log(results)
}
function funcSwitch(routines, i) {
var returnValue;
switch (routines[i][0]) {
case 'A1':
returnValue = A1( routines[i][1] );
break;
case 'B1':
returnValue = B1( routines[i][1] );
break;
case 'C1':
returnValue = C1( routines[i][1] );
break;
}
return returnValue;
}
routineConverter(routines)
Upvotes: 0
Reputation: 804
I left a comment asking about what your problem was as I expect there is a nicer solution. Regardless I have an answer for you. You will need to put the functions you want to call into an object in order for this solution to work. You will also need ES6 support or to babelify your code.
const calls = [["A3",[6]],["B1",["TEST",4,13]],["A10",[2]],["A7",[1,5]]];
const functions = {
A3: function (...args) {
console.log('A3', args);
},
B1: function (...args) {
console.log('B1', args);
},
A10: function (...args) {
console.log('A10', args);
},
A7: function (...args) {
console.log('A7', args);
}
};
const functionCaller = fns =>
fns.map(([fn, ...args]) => functions[fn](...args));
console.log(functionCaller(calls));
Here the functionCaller
function receives the array of invokations, such as those defined at the top, and maps over them, returning an array of their results.
The map works by destructuring the array, with the initial element always being the name of the function and the rest being the arguments, which are separated out into their own array using destructuring syntax and the spread operator
We then take this function name as a key for our object, invoking the particular method requested with the arguments.
When you run the snippet you will see the correct function name as well as the arguments that were passed, but an unpopulated array will be returned as none of the defined functions return anything. If they did we would see this array being populated.
Upvotes: 1
Reputation: 141
I admit it's not the best way, but you can return for example an if at the and of an executed function and you can use this int to start another function.
But that's a compromise solution.
Upvotes: 0