it-swarm.com.ru

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

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

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

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

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

functionQueue.enqueue(doSomething());

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

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

68
Matt

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

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

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

182
Daniel Lew

Канонический ответ размещен здесь


Вот класс Nice 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
});
24
Neal

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

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

6
Dan Davies Brackett

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

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

var funcs = new Array();

funcs['doSomething'] = doSomething;

funcs['doSomething'].call();

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

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

funcs['somethingElse'].call();
6
Mark Biek