javascript - javascript 中类似信号量的队列?

标签 javascript

我有一个变量 can_run,它可以是 1 或 0,然后我有一个函数队列,一旦变量从 0< 切换,它就应该运行1(但一次只有 1 个这样的函数)。

我现在做的是

var can_run=1;
function wait_until_can_run(callback) {
    if (can_run==1) {
        callback();
    } else {
        window.setTimeout(function(){wait_until_can_run(callback)},100);
    }
}

//...somewhere else...

wait_until_can_run( function(){
   can_run=0;
   //start running something
});

//..somewhere else, as a reaction to the task finishing..
can_run=1;

它有效,但是,连续运行大约 100 个超时并没有让我觉得非常有效。信号量之类的东西在这里会很方便;但一般来说,JavaScript 中并不真正需要信号量。

那么,这里要用什么?

编辑:我写了“函数队列”,但正如这里所见,我并不真正关心顺序。

最佳答案

这是一个很好的队列类,您可以使用超时:

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;

})();

可以这样使用:

// 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 演示:http://jsfiddle.net/maniator/dUVGX/


更新为使用 es6 和新的 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;
  }
}

同样可以这样使用:

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

虽然现在如果传递的值是一个 promise 等或一个值,它会自动传递给下一个函数。

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

关于javascript - javascript 中类似信号量的队列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17528749/

相关文章:

javascript - 在javascript中将base64转换为blob

javascript - Safari 中的 SVG 组元素不会触发 Wheel 事件

javascript - 如何在现有 Span 标记之前或之后添加新的 Span 标记

javascript - 根据复选框选择启用@Html.editorFor

javascript - 刷新页面图像后,AngularJS 的 View 中没有显示?

javascript - Messi jQuery 确认框重定向

javascript - 重新 : jQuery; binding global ajax events to non-DOM objects

javascript - 带有 json 数据的 axios post 请求

javascript - 如何在文本区域内预格式化

javascript - 根据选定的单选按钮输入显示/隐藏 DIV