Как написать счетчик асинхронности, то есть счетчик с интерфейсом синхронизации для асинхронного кода, используя только нативный Promise? - PullRequest
0 голосов
/ 26 сентября 2018

Я хочу создать объект, который предоставляет следующий интерфейс:

// 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), используя тольконативный Promise API?

Раскрытие информации У меня уже есть решение для вышеуказанной проблемы, я хочу знать, каков самый элегантный способ сделать это.

Редактировать

Мое оригинальное решение было:

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 в приведенном выше решении не является необходимым.

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Вот как я мог бы написать это, однако извлечение resolveInternal во внешнюю переменную resolve заставляет меня чувствовать, что должно быть лучшее решение.К сожалению, собственный Promise API не предоставляет никаких методов для внешнего разрешения объекта обещания.

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)
0 голосов
/ 26 сентября 2018

Вы бы написали

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;
}
...