1

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>');  
}
5
  • This should only happen if you're executing some asychronus code somewhere, do you run some in any of your functions? Could you provide a runnable snippet? Commented Mar 22, 2018 at 22:06
  • did you try promises Commented Mar 22, 2018 at 22:08
  • Is this Asynchronous? If not you can use setTimeout at an interval of 0. If it is Asynchronous, use promises. Commented Mar 22, 2018 at 22:09
  • 1
    If this is not asynchronous, your functions are guaranteed to finish before the execution of the next one starts. That's due to the synchronous, single-threaded (unless you're using webworkers) nature of Javascript. Commented Mar 22, 2018 at 22:13
  • This is a really weird request. What is the use case? I'm fairly certain there must be a better solution. Commented Mar 22, 2018 at 22:30

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

this looks promising. The thing is that the order isn't predictable. The order is always changing (A3, B1, A10, etc can also be B1, A10, A3, etc)
This will always execute the functions in the order they are provided.
0

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.

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.