Javascript JS/TS中使用async/await的异步有界队列

Javascript JS/TS中使用async/await的异步有界队列,javascript,typescript,asynchronous,async-await,Javascript,Typescript,Asynchronous,Async Await,我正试着用async/await,我有以下代码: class AsyncQueue<T> { queue = Array<T>() maxSize = 1 async enqueue(x: T) { if (this.queue.length > this.maxSize) { // Block until available } this.queue.unshift

我正试着用
async/await
,我有以下代码:

class AsyncQueue<T> {
    queue = Array<T>()
    maxSize = 1

    async enqueue(x: T) {
        if (this.queue.length > this.maxSize) {
            // Block until available
        }

        this.queue.unshift(x)
    }

    async dequeue() {
        if (this.queue.length == 0) {
            // Block until available
        }

        return this.queue.pop()!
    }
}

async function produce<T>(q: AsyncQueue, x: T) {
    await q.enqueue(x)
}

async function consume<T>(q: AsyncQueue): T {
    return await q.dequeue()
}

// Expecting 3 4 in the console
(async () => {
    const q = new AsyncQueue<number>()
    consume(q).then(console.log)
    consume(q).then(console.log)
    produce(q, 3)
    produce(q, 4)
    consume(q).then(console.log)
    consume(q).then(console.log)
})()
类异步队列{
队列=数组()
maxSize=1
异步排队(x:T){
if(this.queue.length>this.maxSize){
//封锁直至可用
}
this.queue.unshift(x)
}
异步出列(){
if(this.queue.length==0){
//封锁直至可用
}
返回此.queue.pop()!
}
}
异步函数生成(q:AsyncQueue,x:T){
等待q.排队(x)
}
异步函数消耗(q:AsyncQueue):T{
返回等待q.出列()
}
//控制台中应为3 4
(异步()=>{
const q=新的异步队列()
消费(q.then)(console.log)
消费(q.then)(console.log)
生产(q,3)
生产(q,4)
消费(q.then)(console.log)
消费(q.then)(console.log)
})()

当然,我的问题在于代码的“块直到可用”部分。我希望能够“暂停”执行,直到发生某些事情(例如,在存在排队之前,将暂停出队,如果有可用空间,则反之亦然)。我觉得我可能需要为此使用协同程序,但我真的想确保我没有错过任何
async/await
magic。

2019年4月17日更新:长话短说,下面的异步信号量实现中有一个bug,它是通过测试发现的。以下是固定版本:

class AsyncSemaphore {
    private promises = Array<() => void>()

    constructor(private permits: number) {}

    signal() {
        this.permits += 1
        if (this.promises.length > 0) this.promises.pop()!()
    }

    async wait() {
        this.permits -= 1
        if (this.permits < 0 || this.promises.length > 0)
            await new Promise(r => this.promises.unshift(r))
    }
}

更新2:上面的代码中似乎隐藏着一个微妙的错误,当尝试使用大小为0的
异步队列时,这个错误变得很明显。语义是有意义的:它是一个没有任何缓冲区的队列,发布者总是等待消费者的存在。阻碍其工作的因素有:

await this.waitingEnqueue.wait()
this.waitingDequeue.signal()
如果仔细观察,您会发现
dequeue()
enqueue()并不完全对称。事实上,如果交换这两条指令的顺序:

this.waitingDequeue.signal()
await this.waitingEnqueue.wait()
然后一切又重新开始;我觉得很直观,在实际等待
排队
发生之前,我们会发出信号,表示有人对
排队(
感兴趣


如果没有广泛的测试,我仍然不确定这是否会重新引入细微的bug。我将把这作为一个挑战;)

您不希望
阻止
,这会冻结脚本-您应该有
排队
出队
等待
承诺,一旦他们等待的内容可用,就立即解决。另外,你应该用
()
调用构造函数。我似乎在把
异步/wait
游戏推得越来越远,我不清楚这一切将如何解决。看看可能的重复。不,你不需要协同程序,您只需要
newpromise
构造函数等待外部发生的事情。然而,您正在实现协同程序。很高兴看到您从答案中得到了一些用处。我被其他事情缠住了,没有时间调试它。我删除了原来的答案,因为它会降低选票,这是理所当然的。
await this.waitingEnqueue.wait()
this.waitingDequeue.signal()
this.waitingDequeue.signal()
await this.waitingEnqueue.wait()