我有一个React Native App,当用户单击按钮时,我调用一个名为_openInterstitial
的函数,该函数返回2个承诺。
代码如下:
_openInterstitial = async () => {
try {
await AdMobInterstitial.requestAdAsync()
await AdMobInterstitial.showAdAsync()
} catch (error) {
console.error(error)
}
}
当我快速点击按钮两次时,它会返回此错误
已经在请求广告,等待之前的承诺。
我如何await
先前的承诺?
我是否需要将另一个await
带到另一个try..catch
块中?
还有其他更简单的方法吗?
答案 0 :(得分:5)
您基本上有三个选择:
_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
设置为false
。 iswaiting
为true
后,只需禁用await
操作即可。