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

时间:2018-09-26 12:28:11

标签: javascript promise async-await counter

我想创建一个暴露以下接口的对象:

// 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秒后解决。

如何仅使用原生counter(countTimes) API来编写Promise

公开信息:我已经a solution遇到了上述问题,想知道什么是最优雅的方法。

修改

我最初的解决方法是:

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 docs for executor function

  

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

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

2 个答案:

答案 0 :(得分:2)

你会写

null

或者,除了将function counter(n) { let i=0, resolve; return { count() { if (++i == n) resolve(); }, finished: new Promise(res => { resolve = res; }) }; } 放在外部变量之外,您也可以这样做

resolve

答案 1 :(得分:2)

这就是我可能写的方式,但是将resolveInternal提取到外部resolve变量中,使我觉得必须有一个更好的解决方案。不幸的是,本机Promise API没有公开任何方法来从外部解析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)