JavaScript是否有多个等待?

时间:2019-05-11 08:30:25

标签: javascript reactjs react-native admob

我有一个React Native App,当用户单击按钮时,我调用一个名为_openInterstitial的函数,该函数返回2个承诺。

代码如下:

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

当我快速点击按钮两次时,它会返回此错误

  

已经在请求广告,等待之前的承诺。

我如何await先前的承诺?

我是否需要将另一个await带到另一个try..catch块中?

还有其他更简单的方法吗?

3 个答案:

答案 0 :(得分:5)

您基本上有三个选择:

  1. 在上一个通话结束之前禁止通话,或者
  2. 将通话排队,仅在前一个通话结束时才开始通话,或者
  3. 拥有对_openInterstitial的呼叫会返回最后一个呼叫的承诺(如果仍未完成)。因此,通话可能不会打开 new 插页式广告,而可能会返回上一次通话的承诺。

对于#1,您至少有两个选择:

如果对_openInterstitial的调用来自UI组件回调,则取决于您所响应的事件类型,您可以通过setState禁用该UI组件,如{{3 }}。例如,如果它是一个按钮,而您正在响应click,则可以保证正常工作。 (我Max Svid's answer。)不能保证所有事件(例如mousemove),但可以保证click及类似事件。 interactiveEventTypeNames checked with Dan Abramov中列出了可以保证的内容。

如果没有,则需要记住您正在执行此操作,并防止再次启动,例如:

_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);
    }
  }
}

理想情况下,除了上面的防护措施之外,您还应该禁用触发此功能的UI。

对于#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被here覆盖。

答案 1 :(得分:3)

一个选择是将进行中的Promise保存在一个半永久变量中,并在调用该方法时返回该进行中的Promise(如果存在)。 Promise解决后,清除持久变量:

_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仅出于封装的目的,这可能是个好主意,但不是必需的。

答案 2 :(得分:3)

我的解决方法是首先使用setState({iswaiting: true}),一旦检索到数据,就将iswaiting设置为falseiswaitingtrue后,只需禁用await操作即可。