反应-为什么循环状态更新先于递归状态更新?

时间:2018-08-20 20:19:41

标签: javascript reactjs loops iteration

单击开始按钮时,它将启动两个计数器。一个使用递归,另一个使用for循环。为什么循环计数器会阻止递归计数器的计数?另外,为什么for循环中的迭代次数有限制?

import React from 'react'
export default class Clock extends React.Component {

state = {
    recursiveCount: 0,
    loopCount: 0,
    stop: false
  }

  clickStart = () => {
      this.setState({
      stop: false
}, () => {
      this.startRecursion()
      this.startLooping()
     })
  }

   startLooping = () => {
       for (let i = 0; i < 1000; i++) {
       setTimeout(() => {
            this.setState({
           loopCount: this.state.loopCount + 1
      })
  }, 1)
    }
  }

   stop = () => {
     this.setState({
     stop: true
})
  }

  startRecursion = () => {
        if (!this.state.stop) {
        setTimeout(() => {
        this.setState({
          recursiveCount: this.state.recursiveCount + 1
        }, () => {
          this.startRecursion()
       })
      }, 1)
    }
  }

  render () {
    return (
     <div>
     <button className = 'button' onClick = 
 {this.clickStart}>Start</button>
     <button className = 'button' id = 'stop' onClick = 
{this.stop}>Stop</button>
     <h1>The recursive function has been recursively called {this.state.recursiveCount} times</h1>
  <h1> The iterative function has been iteratively called {this.state.loopCount} times </h1>
 </div>
)
  }


 }

2 个答案:

答案 0 :(得分:3)

让我们逐步完成代码:

  for (let i = 0; i < 1000; i++) {

它循环1000次。多数民众赞成,并且可能会挂起浏览器一段时间。

 setTimeout(/*callback*/, 1);

您向队列添加了很多超时。现在代码已完成。一秒之后,所有超时同时触发,并且将直接一个接一个地执行。这就是为什么计数器直接从1000跳到2000的原因。

  

为什么循环计数器会阻止递归计数器的计数?

因为只有一个线程,而该线程将被全部同时进入线程队列的1000个回调阻止。递归超时也将在队列中结束,因此它将仅在其他1000个之后执行,这需要时间。

  

还有,为什么for循环中的迭代次数有限制?

循环中没有任何限制,但是,如果阻塞线程时间太长,它将崩溃以帮助客户端:

 while(true );

另外,如chris所指出的那样,在循环中频繁调用setState可能会给您带来麻烦。

答案 1 :(得分:0)

我不认为你想要

for (let i = 0; i < 1000; i++) {
    setTimeout(() => {
      this.setState({
      loopCount: this.state.loopCount + 1
    })
  }, 1)
}

,因为它会排队1000个超时,而无需等待上一个超时完成。而且,阻止。

这是一个工作代码框,其中包含我想要的内容:https://codesandbox.io/s/2xy00529jp

我采取了一些不同的方法-我一直在跟踪超时并在stop上清除它们-我认为使用标志不会出现错误this.state.stop),但我发现自己的方法更简洁。另外,我正在使用this.setState的回调函数-在进行大量顺序状态更新时,新状态值依赖于先前的状态值,这非常重要。浏览this page,了解更多信息。