8

I'm trying to create a function queue with several functions in it. After the creation i want to execute each function in it's turn. But these function have delayed instructions inside of them, so i want to wait for each of the functions to complete its execution before the continuing.

My attempts:

var funqueue = [];
funqueue.push( function() {fun1() });
funqueue.push( function() {fun2() });
funqueue.push( function() {fun3() });
executeFunctionQueue(funqueue);

Where the execute function is:

function executeFunctionQueue(funqueue){
    var fun1=funqueue.pop;
    $.when(fun1()).then(executeFunctionQueue(funqueue));
}

But this does not work. How should i do it?

Sumurai8
  • 20,333
  • 11
  • 66
  • 100
ido4848
  • 213
  • 3
  • 6

6 Answers6

5

Try utilizing .queue() , .promise() ; see also Change easing functions on animations in jQuery queue

function fun1() {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(1)
    }, 1500)
  }).promise().then(msg)
}

function fun2() {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(2)
    }, 1500)
  }).promise().then(msg)
}

function fun3() {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(3)
    }, 1500)
  }).promise().then(msg)
}

var funqueue = [];
funqueue.push(function() {
  return fun1()
});
funqueue.push(function() {
  return fun2()
});
funqueue.push(function() {
  return fun3()
});

function msg(data) {
   if (data === "complete") console.log(data)
   else $("body").append(data + "<br>")
}

function executeFunctionQueue(funqueue) {
  var deferred = funqueue.pop();
  return deferred().then(function() {
      // set `this` within `$.queue()` , `.then()` to empty object `{}`,
      // or other object
      return $({}).queue("fun", $.map(funqueue, function(fn) {
        return function(next) {
          // return `next` function in `"fun"` queue
          return fn().then(next)
        }
      })).dequeue("fun").promise("fun")
      .then(function() {
        // return "complete" string when `fun` queue empty
        return "complete"
      })
    });
}

executeFunctionQueue(funqueue)
.then(msg);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

Alternatively , using $.when()

function executeFunctionQueue(funqueue) {
  return $.when(!!funqueue[funqueue.length - 1] 
                ? funqueue.pop().call().then(function() {
                  return executeFunctionQueue(funqueue)}) 
                : "complete")
}

executeFunctionQueue(funqueue)
.then(function(complete) { 
  console.log(complete) 
});

function fun1() {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(1)
    }, 1500)
  }).promise().then(msg)
}

function fun2() {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(2)
    }, 1500)
  }).promise().then(msg)
}

function fun3() {
  return $.Deferred(function(dfd) {
    setTimeout(function() {
      dfd.resolve(3)
    }, 1500)
  }).promise().then(msg)
}

var funqueue = [];
funqueue.push(function() {
  return fun1()
});
funqueue.push(function() {
  return fun2()
});
funqueue.push(function() {
  return fun3()
});

function msg(data) {
  if (data === "complete") console.log(data)
  else $("body").append(data + "<br>")
}

function executeFunctionQueue(funqueue) {
  return $.when(!!funqueue[funqueue.length - 1] 
                ? funqueue.pop().call().then(function() {
                  return executeFunctionQueue(funqueue)}) 
                : "complete")
}

executeFunctionQueue(funqueue)
.then(msg);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
  • Thank's! That done the job. What if i want to transfer data between these functions? – ido4848 Aug 17 '15 at 10:40
  • @ido4848 _"What if i want to transfer data between these functions?"_ ? Not certain interpret correctly ? Return promise value to `.then()` following `executeFunctionQueue(funqueue)` call ? – guest271314 Aug 18 '15 at 00:24
5

If you have functions that return Promises, this can be done very simply with a function like sequence:

// sequence :: [(undefined -> Promise<undefined>)] -> Promise<undefined>
function sequence(fns) {
    var fn = fns.shift();
    return fn ? fn().then(sequence.bind(null, fns)) : Promise.resolve(undefined);
}

sequence assumes that your asynchronous/Promise-returning functions do not take any inputs and do not produce any outputs (that they are merely being called for side-effects.)

An example usage of the sequence function is:

sequence([f1, f2, f3]);

function f1() {
    return new Promise(function (res) {
        setTimeout(function () {
            console.log('f1');
            res();
        }, 100);
    });
}

function f2() {
    return new Promise(function (res) {
        setTimeout(function () {
            console.log('f2');
            res();
        }, 1100);
    });
}

function f3() {
    return new Promise(function (res) {
        setTimeout(function () {
            console.log('f3');
            res();
        }, 10);
    });
}

This will log out 'f1', 'f2', and 'f3' in order with the varying, specified time delays in between.

Noah Freitas
  • 17,240
  • 10
  • 50
  • 67
1

use deferred/promise pattern to execute functions on other function complete.

var createQueue = function () {
    var d = $.Deferred(),
        p = d.promise(),
        triggerQueue = function () {
            d.resolve();
        };

    return {
        addToQueue: p.then,
        triggerQueue: triggerQueue
    }
};


var cq = createQueue();
cq.addToQueue(function () {
    console.log("hi");
}).then(function () {
    console.log("hello");
});
cq.triggerQueue();
venkat7668
  • 2,657
  • 1
  • 22
  • 26
1

Use this

function executeFunctionQueue(funqueue){
    if(!funqueue.length){
     return 
    }
    var fun1=funqueue.pop();
    $.when(fun1()).then(function(){
           executeFunctionQueue(funqueue)
     });
}

Or even this if queued functions are not asynchronous.

function executeFunctionQueue(funqueue){
    var fun=funqueue.pop();
    fun()
    if(!funqueue.length){
     return 
    }
    executeFunctionQueue(funqueue);
}
vinayakj
  • 5,591
  • 3
  • 28
  • 48
1
  1. First create an array of functions as given:

var array_of_functions = [function1, function2, function3, function4];
  1. When you want to execute a given function in the array try this:

array_of_functions[index]('mystring');
Domain
  • 11,562
  • 3
  • 23
  • 44
1

In order to make a clean queue, your asynchronous functions will need to somehow signify when they are done, or the next function won't know when to begin. This means you cannot pass in just any old function; they'll need to follow some format. I'd suggest taking a done callback as the first parameter in your function calls. This way, you can support both synchronous and asynchronous functions.

var processQueue = function nextStep(queue) {
  var next = queue.shift();
  next && next(function() { nextStep(queue); });
}

function fun1(done) {
  setTimeout(function() {
    console.info('1');
    done();
  }, 1000);
}

function fun2(done) {
  console.info('2');
  done();
}

processQueue([fun1, fun2]);

// >> 1 second wait
// >> 1
// >> 2
rrowland
  • 2,734
  • 2
  • 17
  • 32