Как хранить функции javascript в очереди, чтобы они выполнялись в конце концов?

Я создал класс Queue в javascript, и я хотел бы хранить функции как данные в очереди. Таким образом, я могу создавать запросы (вызовы функций) и отвечать на них, когда мне нужно (фактически выполняя функцию).

Есть ли способ сохранить функцию как данные, чем-то похожую на

.setTimeout("doSomething()", 1000);

кроме как было бы

functionQueue.enqueue(doSomething());

Где он будет хранить doSomething() в качестве данных, поэтому, когда я получу данные из очереди, функция будет выполнена.

Я предполагаю, что я должен был бы сделать doSomething() в кавычках -> "doSomething()" и как-нибудь, как заставить его вызывать функцию, используя строку, кто-нибудь знает, как это можно сделать?

4 ответа

Решение

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

// Create your functions, in a variety of manners...
// (The second method is preferable, but I show the first for reference.)
function fun1() { alert("Message 1"); };
var fun2 = function() { alert("Message 2"); };

// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);

// Remove and execute the first function on the queue
(funqueue.shift())();

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

// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
    return function() {
        fn.apply(context, params);
    };
}

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

// Create my function to be wrapped
var sayStuff = function(str) {
    alert(str);
}

// Wrap the function.  Make sure that the params are an array.
var fun1 = wrapFunction(sayStuff, this, ["Hello, world!"]);
var fun2 = wrapFunction(sayStuff, this, ["Goodbye, cruel world!"]);

// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);

// Remove and execute all items in the array
while (funqueue.length > 0) {
    (funqueue.shift())();   
}

Этот код может быть улучшен, если позволить оболочке использовать массив или серию аргументов (но это может привести к путанице в примере, который я пытаюсь сделать).

Канонический ответ выложен здесь


Вот хороший класс Queue, который вы можете использовать без использования тайм-аутов:

var Queue = (function(){

    function Queue() {};

    Queue.prototype.running = false;

    Queue.prototype.queue = [];

    Queue.prototype.add_function = function(callback) { 
        var _this = this;
        //add callback to the queue
        this.queue.push(function(){
            var finished = callback();
            if(typeof finished === "undefined" || finished) {
               //  if callback returns `false`, then you have to 
               //  call `next` somewhere in the callback
               _this.next();
            }
        });

        if(!this.running) {
            // if nothing is running, then start the engines!
            this.next();
        }

        return this; // for chaining fun!
    }

    Queue.prototype.next = function(){
        this.running = false;
        //get the first element off the queue
        var shift = this.queue.shift(); 
        if(shift) { 
            this.running = true;
            shift(); 
        }
    }

    return Queue;

})();

Это можно использовать так:

var queue = new Queue;
queue.add_function(function(){
   //start running something
});
queue.add_function(function(){
   //start running something 2
});
queue.add_function(function(){
   //start running something 3
});

Вы также можете использовать метод .call() объекта функции.

function doSomething() {
    alert('doSomething');
}

var funcs = new Array();

funcs['doSomething'] = doSomething;

funcs['doSomething'].call();

Кроме того, вы также можете добавить функцию непосредственно в очередь:

funcs['somethingElse'] = function() {
    alert('somethingElse');
};

funcs['somethingElse'].call();

Обратитесь к функции, которую вы храните без () в конце. doSomething переменная (которая является функцией); doSomething() инструкция для выполнения функции

Позже, когда вы используете очередь, вы захотите что-то вроде (functionQueue.pop())() - то есть выполнить functionQueue.pop, а затем выполнить возвращаемое значение этого вызова pop.

Другие вопросы по тегам