我有一个变量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中并不真正需要信号量.
那么,在这里使用什么?
编辑:我写过“功能队列”但是如此处所见,我并不关心订单.
解决方法
这是一个很好的Queue类,您可以在不使用超时的情况下使用它:
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);
小提琴演示:http://jsfiddle.net/maniator/dUVGX/
更新为使用es6和新es6 Promises:
class Queue { constructor(autorun = true,queue = []) { this.running = false; this.autorun = autorun; this.queue = queue; this.prevIoUsValue = undefined; } 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);