我有一个进行API调用的异步函数。它以这种形式传递给setTimeout():
componentDidMount() {
this.pollingId = setTimeout(this.someOtherFunc, 2000)
}
componentWillUnmount() {
clearTimeout(this.pollingId)// clears an old polling id initialised in previous polling call
}
someOtherFunc = async () => {
await axios.get('/some/api')
clearTimeout(this.pollingId)
if (someConditionToContinuePolling) {
this.pollingId = setTimeout(this.someOtherFunc, 2000) // this will not return a value and update this.pollingId before reloadFunc is over
}
}
因此,如果API请求需要更长的时间,当我在处理请求时导航到其他页面时,componentWillUnmount会清除旧的pollingId,而不清除另一个。是否有一种方法使setTimeout不等待异步回调完成返回其id?
:我不介意当前的请求完成,我的问题是,如果我导航到另一个页面,而请求正在处理,componentWillUnmount清除以前的pollingId
,和this.someOtherFunc()通过setTimeout()不断调用自己,永远不会停止轮询
正如mdn所说的setTimeout的返回值:
返回的timeoutID是一个正整数值,用于标识调用setTimeout()创建的计时器。这个值可以是传递给
clearTimeout()
取消超时。
所以你可以收集所有的timeoutID's
,把它们放在一个数组中,用这些id运行clearTimeout
。让我们创建一个数组来存储所有timeoutID,代码如下所示:
componentDidMount() {
this.pollingId = setTimeout(this.reloadFunc, 2000)
this.addIdTimeoutIds(this.pollingId)
}
someOtherFunc = () => {
this.pollingId = setTimeout(this.reloadFunc, 2000)
this.addIdTimeoutIds(this.pollingId)
}
componentWillUnmount() {
this.timeoutIDs.forEach(timeoutId => clearTimeout(timeoutId)
}
addIdTimeoutIds = (pollingId) =>
this.timeoutIDs.push(pollingId)
更新:如果你想中止你的请求,你可以使用AbortController(特别感谢Pilchard)。
这是一个使用Axios的例子:
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// cancel the request
controller.abort()
我意识到根本问题与清除正确的pollingId
无关。它是关于在this.someOtherFunc()中中止setTimeout调用的新初始化。由于setTimeout()正在调用它所在的函数,因此我遇到了当前回调调用并在其中再次启动新的setTimeout的情况。
@pilchard关于中止已经在运行的函数调用的回答促使我选择了这个解决方案。非常感谢!
只是添加了一个标志来停止轮询。
componentDidMount() {
this.pollingId = setTimeout(this.someOtherFunc, 2000)
}
componentWillUnmount() {
clearTimeout(this.pollingId)// clears an old polling id initialised in previous polling call
this.stopPolling = true
}
someOtherFunc = async () => {
await axios.get('/some/api')
clearTimeout(this.pollingId)
if (someConditionToContinuePolling && !stopPolling) {
this.pollingId = setTimeout(this.someOtherFunc, 2000) // this will not return a value and update this.pollingId before reloadFunc is over
}
}