Semaphore-like queue in javascript?

前端 未结 3 730
小蘑菇
小蘑菇 2020-12-05 08:58

I have a variable can_run, that can be either 1 or 0, and then I have a queue of functions, that should be run as soon as the variable is switched from 0<

3条回答
  •  长情又很酷
    2020-12-05 09:29

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

    var Queue = (function () {
    
        Queue.prototype.autorun = true;
        Queue.prototype.running = false;
        Queue.prototype.queue = [];
    
        function Queue(autorun) {
            if (typeof autorun !== "undefined") {
                this.autorun = autorun;
            }
            this.queue = []; //initialize the queue
        };
    
        Queue.prototype.add = 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.dequeue();
                }
            });
    
            if (this.autorun && !this.running) {
                // if nothing is running, then start the engines!
                this.dequeue();
            }
    
            return this; // for chaining fun!
        };
    
        Queue.prototype.dequeue = function () {
            this.running = false;
            //get the first element off the queue
            var shift = this.queue.shift();
            if (shift) {
                this.running = true;
                shift();
            }
            return shift;
        };
    
        Queue.prototype.next = Queue.prototype.dequeue;
    
        return Queue;
    
    })();
    

    It can be used like so:

    // passing false into the constructor makes it so 
    // the queue does not start till we tell it to
    var q = new Queue(false).add(function () {
        //start running something
    }).add(function () {
        //start running something 2
    }).add(function () {
        //start running something 3
    });
    
    setTimeout(function () {
        // start the queue
        q.next();
    }, 2000);
    

    Fiddle Demo: http://jsfiddle.net/maniator/dUVGX/


    Updated to use es6 and new es6 Promises:

    class Queue {  
      constructor(autorun = true, queue = []) {
        this.running = false;
        this.autorun = autorun;
        this.queue = queue;
      }
    
      add(cb) {
        this.queue.push((value) => {
            const finished = new Promise((resolve, reject) => {
            const callbackResponse = cb(value);
    
            if (callbackResponse !== false) {
                resolve(callbackResponse);
            } else {
                reject(callbackResponse);
            }
          });
    
          finished.then(this.dequeue.bind(this), (() => {}));
        });
    
        if (this.autorun && !this.running) {
            this.dequeue();
        }
    
        return this;
      }
    
      dequeue(value) {
        this.running = this.queue.shift();
    
        if (this.running) {
            this.running(value);
        }
    
        return this.running;
      }
    
      get next() {
        return this.dequeue;
      }
    }
    

    It can be used in the same way:

    const q = new Queue(false).add(() => {
        console.log('this is a test');
    
        return {'banana': 42};
    }).add((obj) => {
        console.log('test 2', obj);
    
        return obj.banana;
    }).add((number) => {
        console.log('THIS IS A NUMBER', number)
    });
    
    // start the sequence
    setTimeout(() => q.next(), 2000);
    

    Although now this time if the values passed are a promise etc or a value, it gets passed to the next function automatically.

    Fiddle: http://jsfiddle.net/maniator/toefqpsc/

提交回复
热议问题