web-dev-qa-db-fra.com

Comment stocker les fonctions javascript dans une file d'attente pour qu'elles soient éventuellement exécutées

J'ai créé une classe de file d'attente en javascript et je voudrais stocker des fonctions sous forme de données dans une file d'attente. De cette façon, je peux créer des demandes (appels de fonction) et y répondre quand j'en ai besoin (en fait, exécuter la fonction).

Existe-t-il un moyen de stocker une fonction en tant que données, quelque peu similaire à

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

sauf que ce serait

functionQueue.enqueue(doSomething());

Où il stockerait doSomething () en tant que données, donc lorsque je récupère les données de la file d'attente, la fonction est exécutée.

Je suppose que je devrais avoir doSomething () entre guillemets -> "doSomething ()" et certains comment le faire appeler la fonction en utilisant une chaîne, quelqu'un sait comment cela pourrait être fait?

70
Matt

Toutes les fonctions sont en fait des variables, il est donc assez facile de stocker toutes vos fonctions dans un tableau (en les référençant sans le ()):

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

Cela devient un peu plus complexe si vous souhaitez passer des paramètres à vos fonctions, mais une fois que vous avez configuré le cadre pour le faire une fois, cela devient facile à chaque fois par la suite. Essentiellement, vous allez créer une fonction wrapper qui, lorsqu'elle est invoquée, déclenche une fonction prédéfinie avec un contexte et un ensemble de paramètres particuliers:

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

Maintenant que nous avons une fonction utilitaire pour l'encapsulation, voyons comment elle est utilisée pour créer de futures invocations de fonctions:

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

Ce code pourrait être amélioré en autorisant l'encapsuleur à utiliser un tableau ou une série d'arguments (mais cela brouillerait l'exemple que j'essaie de faire).

182
Daniel Lew

Réponse canonique publiée ici


Voici une classe Nice Queue que vous pouvez utiliser sans l'utilisation de délais d'attente:

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;

})();

Il peut être utilisé comme ceci:

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

Reportez-vous à la fonction que vous stockez sans le () à la fin. doSomething est une variable (qui se trouve être une fonction); doSomething() est une instruction pour exécuter la fonction.

Plus tard, lorsque vous utiliserez la file d'attente, vous voudrez quelque chose comme (functionQueue.pop())() - c'est-à-dire, exécutez functionQueue.pop, puis exécutez la valeur de retour de cet appel à pop.

6

Vous pouvez également utiliser la méthode . Call () d'un objet fonction.

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

var funcs = new Array();

funcs['doSomething'] = doSomething;

funcs['doSomething'].call();

De plus, vous pouvez également ajouter la fonction directement à la file d'attente:

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

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