Кэшировать значение, полученное из обратного вызова слушателя - PullRequest
4 голосов
/ 06 августа 2020

ПРИМЕЧАНИЕ: Кэширование JavaScript результаты обещания не применяется, потому что этот вопрос не касается API, который вызывает обратный вызов слушателя при изменении состояния (что означает, что API сохраняет функцию слушателя и может вызывать его несколько раз, когда его состояние обновляется).

У меня есть тип объекта состояния State.

Теперь у меня есть API API.addEventListener(), который принимает слушатель типа function(!State):undefined и логическое repeating. При вызове этот API сохранит обратный вызов слушателя и вызовет его с помощью объекта State, если

  • a State станет доступным (от несуществования к существованию)
  • новый State объект становится доступным (мутация), если repeating истинно.

Первоначально, всякий раз, когда я вызываю doStuff() для выполнения моего logi c, я буду вызывать API.addEventListener(), чтобы получить Самый последний объект State:

/**
 * @return {!Promise{!State}}
 */
function getStatePromise() {
  return new Promise(resolve => {
    API.addEventListener(resolve, /* repeating */ false);
  });
}

function doStuff() {
  getStatePromise().then(state => {
    // my logic
  });
}

doStuff() может вызываться несколько раз в разных точках моей программы.

Теперь я хотел бы кэшировать результат, полученный из API.getState() в постоянном объекте в моем JS скрипте, и пусть код обновит кеш, когда станет доступен новый State. Я не хочу менять doStuff(), потому что это довольно сложно. Можно ли просто изменить getStatePromise() для этого?

Моя текущая попытка:

let cacheStorage = {}; // or window.localStorage, but it's beside the point

/**
 * @return {!Promise{!State}}
 */
function getStatePromise() {
  if (cacheStorage.state !== undefined) {
    return Promise.resolve(cacheStorage.state);
  }

  return new Promise(resolve => {
    API.addEventListener(newState => {
        cacheStorage.state = newState;
        resolve(newState); // ??? what if the listener is called again?
    }, /* repeating */ true);
  });
}

function doStuff() {
  getStatePromise().then(state => {
    // my logic
  });
}

Когда doStuff() вызывается в первый раз, cacheStorage пусто, поэтому getStatePromise() получит объект State, заполнит кеш и вернет обещание, которое преобразуется в объект State. Затем, когда doStuff() вызывается во второй раз, он просто возвращает обещание, которое разрешается кэшированному объекту State.

Однако проблема в том, что новый State становится доступным позже , API снова вызовет обратный вызов слушателя, что означает, что resolve() будет снова вызван (см. ??? в коде). Это звучит неправильно, потому что это разрешает обещание, которое уже выполнено. Как мне это исправить?

Изменить: это исправление?

Заменить

return new Promise(resolve => {
    API.addEventListener(newState => {
        cacheStorage.state = newState;
        resolve(newState); // ??? what if the listener is called again?
    }, /* repeating */ true);
  });

на

return new Promise(resolve => {
    let initialCall = true;
    API.addEventListener(newState => {
        cacheStorage.state = newState;
        if (initialCall) {
          resolve(newState);
          initialCall = false;
        }
    }, /* repeating */ true);
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...