2

Sorry, if this question was asked before - i haven't found the answer for my case.

I have one function, which will be called again and again asynchronously.
I need to avoid concurrent execution of this function.

Here the example:

const q = // some kind of queue;

let v = 0;
const fun = (arg) => {
    console.log('v', v)
    setTimeout(() => {
        v = v + arg;
        // return true;
        q.next()
    }, 1000)
}


q.add(fun(2))
q.add(fun(3))
q.add(fun(4))
q.add(fun(5))

This is the logs i want to see at the end:

v 0
v 2
v 5
v 9
v 14
6
  • Take a look at the async library. It does this for you github.com/caolan/async Particularly the "series(...)" function Commented Jun 27, 2016 at 18:31
  • fun() doesn't return anything, what are you expecting to put in the queue? Commented Jun 27, 2016 at 18:54
  • @Barmar i intend to put there quite complicated functions with async rest calls. I need to have way to say "this function finished, check if there is next one" in each of queued functions Commented Jun 27, 2016 at 18:56
  • Is the argument to q.add() supposed to be a function to call? You're not passing a function, you're calling the function and passing its value to q.add(). Commented Jun 27, 2016 at 18:57
  • and i need to be able to add any quantity of new functions in the queue any time (there might be no functions for minutes and there might be dozen functions added within a second_ Commented Jun 27, 2016 at 18:58

3 Answers 3

3

You can just use an array.

Note that my code's output is slightly different from yours—I don't get "v 14". I'm not sure why you expect that output... you're queueing up four function calls but expect five lines of output?

const q = [];

let v = 0;
function fun (arg) {
  console.log('v', v);
  setTimeout(() => {
    v = v + arg;
    var next = q.shift();
    if (next) { next(); }
  });
}

q.push(() => { fun(2); });
q.push(() => { fun(3); });
q.push(() => { fun(4); });
q.push(() => { fun(5); });

q.shift()(); // run the first one

// OUTPUT:
// v 0
// v 2
// v 5
// v 9

EDIT

Here's perhaps a better version that has the added advantage that it will work properly no matter when things are enqueued. In the above code, you have to manually start running things, and once the queue is exhausted, nothing later added will ever be run. In the below FunctionQueue class, execution happens automatically whenever there's at least one function to run:

class FunctionQueue {
  constructor() {
    this.queue = [];
    this.running = false;
  }

  go() {
    if (this.queue.length) {
      this.running = true;
      this.queue.shift()(() => { this.go(); });
    } else {
      this.running = false;
    }
  }

  add(func) {
    this.queue.push(func);

    if(!this.running) {
      this.go();
    }
  }
}

let v = 0;
function fun (arg, cb) {
  console.log('v', v);
  v += arg;
  setTimeout(cb, 100);
}

const q = new FunctionQueue();
// Execution will automatically start once something is enqueued.
q.add((cb) => { fun(2, cb); });
q.add((cb) => { fun(3, cb); });
q.add((cb) => { fun(4, cb); });
q.add((cb) => { fun(5, cb); });

// At this point, nothing's running anymore.

// Enqueueing something much later will resume execution again.
setTimeout(() => {
  q.add((cb) => { fun(6, cb); });
}, 1000);

// OUTPUT:
// v 0
// v 2
// v 5
// v 9
// v 15
Sign up to request clarification or add additional context in comments.

2 Comments

how do i add new one in 10 minutes or so after initial execution?
@stkvtflw See my edit, which should handle that case nicely.
0

This will be started with fun() and continue to run while there are increment definitions left in the queue:

const queue = [];

const fun = (start) => {
    start = start || 0
    console.log('v', start)
    setTimeout(() => {
        if(queue.length > 0) {
          const increment = queue.shift();
          fun(start + increment);
        }
    }, 1000)
}

queue.push(2)
queue.push(3)
fun()
queue.push(4)
queue.push(5)

Note that depending on your browser, the const keyword may not be supported and needs to be transpiled to ES5 or replaced with the var keyword.

Comments

0

You can make use of Promise. Any resolution of first one, call the second one and so on..

let v = 0;
const fun = (arg) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('v', v)
        v = v + arg;
        resolve(true);
    }, 1000)
  });
}

var promise = func(0);
for (var i =1; i< 10; i++){
  (function(n){
    promise = promise.then(()=>{
       return func(n);
    });
  })(i);
}

1 Comment

how do i add new one in 10 minutes or so after initial execution?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.