我有一个变量 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 等或一个值,它会自动传递给下一个函数。
关于javascript - javascript 中类似信号量的队列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17528749/