如何编写异步计数器,即仅使用本机 Promise 的异步代码具有同步接口的计数器?



我想创建一个公开以下接口的对象:

// Create the object that counts to three
const c = counter(3);
// c.finished is a promise that resolves when c.count() is invoked three times
c.finished.then(() => console.log('counted three times!'));
// Somewhere else, c.count() is invoked in async body
setTimeout(() => c.count(), 500);
setTimeout(() => c.count(), 1000);
setTimeout(() => c.count(), 1500);

我希望c.finished在 1.5 秒后解决。

如何仅使用本机PromiseAPI编写counter(countTimes)

披露我已经有解决了上述问题,想知道什么是最优雅的方法。

编辑

我最初的解决方案是:

class AsyncCounter {
constructor(countTimes) {
let currentCount = 0;
this.countTimes = countTimes;
this.ready = new Promise(resolveReady => {
this.finished = new Promise(resolveFinished => {
const count = () => {
currentCount++;
if (currentCount >= this.countTimes) {
resolveFinished();
}
return currentCount;
};
this.count = () => this.ready.then(() => count());
resolveReady();
});
});
}
}
const counter = countTimes => new AsyncCounter(countTimes);

正如@Bergi所建议的,并根据执行器功能的MDN文档:

在 Promise 构造函数甚至返回 创建的对象

因此,上述解决方案中的ready承诺是不必要的。

你会写

function counter(n) {
let i=0, resolve;
return {
count() {
if (++i == n) resolve();
},
finished: new Promise(res => {
resolve = res;
})
};
}

或者,与其将resolve放在外部变量中,您也可以这样做

function counter(n) {
let i=0;
const res = {};
res.finished = new Promise(resolve => { 
res.count = () => {
if (++i == n) resolve();
};
});
return res;
}

以下是我可能编写它的方式,但是将resolveInternal提取到外部resolve变量中让我觉得必须有更好的解决方案。遗憾的是,本机PromiseAPI 不会公开任何方法来外部解析 promise 对象。

function counter(max) {
let resolve = null;
const finished = new Promise(resolveInternal => {
resolve = resolveInternal
})
const count = () => {
if (!--max) resolve()
}
return {
count,
finished
}
}
const c = counter(3)
c.finished.then(() => console.log("counted three times!"))
setTimeout(() => c.count(), 500)
setTimeout(() => c.count(), 1000)
setTimeout(() => c.count(), 1500)

最新更新