Несколько ждет в JavaScript? - PullRequest
3 голосов
/ 11 мая 2019

У меня есть приложение React Native, где, когда пользователь нажимает кнопку, я вызываю функцию с именем _openInterstitial, которая возвращает 2 обещания.

Код выглядит следующим образом:

_openInterstitial = async () => {
    try {
      await AdMobInterstitial.requestAdAsync()
      await AdMobInterstitial.showAdAsync()
    } catch (error) {
      console.error(error)
    }
  }

Когда я дважды быстро нажимаю на кнопку, появляется сообщение об ошибке

Объявление уже запрашивается, дождитесь предыдущего обещания.

Как мне awaitпредыдущее обещание?

Нужно ли взять другой await в другой try..catch блок?

Есть ли какой-нибудь другой более простой способ?

Ответы [ 3 ]

5 голосов
/ 11 мая 2019

Обычно у вас есть три варианта:

  1. Запретить вызовы до завершения предыдущего вызова, или
  2. Очередь вызовов, начиная каждый только после завершения предыдущего, или
  3. Позвонить на _openInterstitial вернуть обещание последнего звонка, если он все еще не выполнен.Таким образом, вызов не может открыть новый междоузлия, он может просто вернуть обещание от предыдущего вызова.

Для # 1 у вас есть как минимум два варианта:

Если вызов _openInterstitial поступает от обратного вызова компонента пользовательского интерфейса, в зависимости от типа события, на которое вы реагируете, вы можете отключить этот компонент пользовательского интерфейса с помощью setState, как показано в Макс Макс Свид .Например, если это кнопка, а вы отвечаете на click, это гарантированно сработает.(Я проверил с Даном Абрамовым .) Это не гарантируется для всех событий (например, mousemove), но для click и подобных.Те, где это гарантировано, перечислены в interactiveEventTypeNames здесь .

Если нет, вам нужно помнить, что вы находитесь в процессе выполнения этого и предотвратить запуск другого, чего-тонапример:

_openInterstitialEnabled = true;
_openInterstitial = async () => {
  if (this._openInterstitialEnabled) {
    try {
      this._openInterstitialEnabled = false;
      await AdMobInterstitial.requestAdAsync();
      await AdMobInterstitial.showAdAsync();
      this._openInterstitialEnabled = true;
    } catch (error) {
      console.error(error);
    }
  }
}

В идеале, в дополнение к вышеприведенной защите, вы также должны отключить пользовательский интерфейс, который вызывает эту функцию.

Для # 2 (в очереди) запомните предыдущее обещание идождитесь его завершения, прежде чем начинать следующую операцию, что-то вроде:

_lastOpenInterstitial = Promise.resolve();
_openInterstitial = () => {
  return this._lastOpenInterstitial = this._openInterstitialWorker();
};
_openInterstitialWorker = async () => {
  try {
    await this._lastOpenInterstitial;
    await AdMobInterstitial.requestAdAsync();
    await AdMobInterstitial.showAdAsync();
  } catch (error) {
    console.error(error);
  }
};

или несколько проще:

_lastOpenInterstitial = Promise.resolve();
_openInterstitial = () => {
  return this._lastOpenInterstitial = this._lastOpenInterstitial
    .then(AdMobInterstitial.requestAdAsync) // Assuming it doesn't care about `this`, use an arrow function wrapper if it does
    .then(AdMobInterstitial.showAdAsync)    // Same assumption
    .catch(error => { console.error(error); });
};

или если вы хотите вернуться к async функции каккак можно раньше:

_lastOpenInterstitial = Promise.resolve();
_openInterstitial = () => {
  return this._lastOpenInterstitial = this._lastOpenInterstitial.then(async() => {
    await AdMobInterstitial.requestAdAsync();
    await AdMobInterstitial.showAdAsync();
  }).catch(error => { console.error(error); });
};

Во всех них я предположил, что это какой-то класс, и это объявления открытых свойств с использованием синтаксиса полей класса, но его легко настроить при необходимости, если янеправильно угадал.

# 3 покрывается ответом CertainPerformance .

3 голосов
/ 11 мая 2019

Мой обходной путь для этого - сначала setState({iswaiting: true}), после получения данных установите iswaiting в false.Если iswaiting равно true, просто отключите действие await.

3 голосов
/ 11 мая 2019

Один из вариантов - сохранить текущее обещание в полупостоянной переменной и вернуть текущее обещание, если оно существует при вызове метода. Когда Обещание разрешится, очистите постоянную переменную:

_openInterstitial = (() => {
  let ongoingProm;
  const getProm = async () => {
    try {
      await AdMobInterstitial.requestAdAsync()
      await AdMobInterstitial.showAdAsync()
    } catch (error) {
      console.error(error)
    }
  };
  return () => {
    if (ongoingProm) {
      return ongoingProm;
    }
    ongoingProm = getProm()
      .then(() => {
        ongoingProm = null;
      });
    return ongoingProm;
  };
})();

IIFE - просто для инкапсуляции, это, вероятно, хорошая идея, но не обязательно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...