В JavaScript, как выполнить следующую функцию из массива функций

У меня есть ряд функций, как в:

funcArray = [func1, func2, func3];

Когда в данной функции я хочу выполнить следующую функцию в массиве. Как мне это сделать? Вот мой основной скелет:

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.

}

Я не могу использовать функцию indexOf, как и для массива строк или чисел. ПРИМЕЧАНИЕ. Этот вопрос, похоже, похож на этот и тот, на который он ссылается. Однако это другой вопрос.

Я хочу изменить последовательность обработки, просто изменив массив. Это цель. Было бы полезно оценить более эффективный подход.

Уточнение: основываясь на некоторых комментариях: funcArray является глобальным.

Целью является внедрение промежуточного программного обеспечения для HTTP-модуля Node.js максимально простым и эффективным образом без использования сторонних модулей.

Ответ 1

Если func1 закрывается над funcArray, вы не можете его охватить и найти func2 и выполнить его, а также не должны. Даже если func1 закрывается над funcArray, было бы плохое разделение проблем для func1 чтобы протянуть руку и найти себя в funcArray а затем выполнить func2.

Вместо этого, есть другой код, который отвечает за запуск функций.

Если они синхронны

Если функции завершают свою работу синхронно, то это просто:

funcArray.forEach(fn => fn());

или же

for (const fn of funcArray) {
    fn();
}

или если результат одной функции должен быть передан следующему, вы можете использовать reduce:

const finalResult = funcArray.reduce((previousResult, fn) => fn(previousResult), undefined);

... где undefined - это значение, func1.

Если они асинхронны

Если они не выполняют свою работу синхронно, вам необходимо предоставить им способ уведомить своего звонящего, что они завершили свою работу. Обещания - хороший, стандартный способ сделать это, но вместо этого вы можете использовать простые обратные вызовы.

Если вы заставляете их возвращать обещания, например, вы можете использовать старое обещание, reduce трюк:

funcArray.reduce((p, fn) => {
    return p.then(() => {
        fn();
    });
}, Promise.resolve());

или если результат одной функции должен быть передан следующему:

funcArray.reduce((p, fn) => {
    return p.then(fn);
}, Promise.resolve());

Вы можете предоставить аргумент для Promise.resolve чтобы установить значение для перехода к func1 (без него он получит undefined).

Ответ 2

Вы можете привязать к функции индекс, где он находится в массиве, чтобы вы могли использовать этот индекс, чтобы получить и вызвать следующую функцию:

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();
}

Ответ 3

Вы можете получить текущее имя функции с arguments.callee.name, выполнить цикл через массив функций и вызвать следующую функцию:

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

Ответ 4

Я не знаю, нужны ли ваши функции определенным параметрам, но это первое, что мне пришло в голову.

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();
  });

Ответ 5

Принятый ответ и другие комментарии действительно помогли мне, но способ, которым я его реализовал, выглядит следующим образом:

//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];
}

Последовательность выполняемых функций легко управляется через массив funcArray. Количество или тип аргументов не фиксируется для каждой функции. Кроме того, функции управляют, если они должны остановить цепочку или продолжить следующую функцию.

Это очень просто понять, требуя базовых навыков Javascript. Нет накладных расходов на использование обещаний.

"global" заменяется "окном" для браузера. Это реализация Node.js. Однако использование имен функций в массиве будет нарушено, если вы уменьшите код JS. Поскольку я собираюсь использовать его на сервере, я не рассчитываю его минимизировать.