Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I store javascript functions in a queue for them to be executed eventually [duplicate]

All functions are actually variables, so it's actually pretty easy to store all your functions in array (by referencing them without the ()):

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

This becomes a bit more complex if you want to pass parameters to your functions, but once you've setup the framework for doing this once it becomes easy every time thereafter. Essentially what you're going to do is create a wrapper function which, when invoked, fires off a predefined function with a particular context and parameter set:

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

Now that we've got a utility function for wrapping, let's see how it's used to create future invocations of functions:

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

This code could be improved by allowing the wrapper to either use an array or a series of arguments (but doing so would muddle up the example I'm trying to make).


Canonical answer posted here


Here is a nice Queue class you can use without the use of timeouts:

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;

})();

It can be used like so:

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

Refer to the function you're storing without the () at the end. doSomething is a variable (that happens to be a function); doSomething() is an instruction to execute the function.

Later on, when you're using the queue, you'll want something like (functionQueue.pop())() -- that is, execute functionQueue.pop, and then execute the return value of that call to pop.


You can also use the .call() method of a function object.

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

var funcs = new Array();

funcs['doSomething'] = doSomething;

funcs['doSomething'].call();

In addition, you can also add the function directly to the queue:

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

funcs['somethingElse'].call();