简体   繁体   English

反应-为什么循环状态更新在递归状态更新之前?

[英]React— why do looped state updates precede recursive state updates?

When you click the start button, it starts two counters. 当您单击开始按钮时,它将启动两个计数器。 One uses recursion and the other uses a for loop. 一个使用递归,另一个使用for循环。 Why does the looping counter block the counting of the recursive counter? 为什么循环计数器会阻止递归计数器的计数? Also, why is there a limit for the number of iterations in the for loop? 另外,为什么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>
)
  }


 }

Lets step through the code: 让我们逐步检查代码:

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

It loops 1000 times. 它循环1000次。 Thats much and will probably hang the browser for a bit. 多数民众赞成,并且可能会挂起浏览器一段时间。

 setTimeout(/*callback*/, 1);

You add a lot of timeouts to the queue. 您将很多超时添加到队列中。 Now the code is done. 现在代码已完成。 One tick later, all timeouts fire at the same time, and will be executed directly one after another. 一秒之后, 所有超时都将同时触发,并将直接一个接一个地执行。 Thats why the counter directly jumps from 1000 to 2000. 这就是为什么计数器直接从1000跳到2000的原因。

Why does the looping counter block the counting of the recursive counter? 为什么循环计数器会阻止递归计数器的计数?

Cause there is only one thread, and that will be blocked by the 1000 callbacks that all get into the threads queue at the same time. 原因是只有一个线程,而该线程将被全部同时进入线程队列的1000个回调阻止。 The recursive timeout will also end in the queue, therefore it will only be executed after the 1000 others, which takes time. 递归超时也将在队列中结束,因此它将仅在1000个超时之后执行。

Also, why is there a limit for the number of iterations in the for loop? 另外,为什么for循环中的迭代次数有限制?

There is no number of limitations in a loop, however if you block the thread for too long it crashes to help the client: 循环中没有任何限制,但是,如果将线程阻塞的时间太长,它将崩溃以帮助客户端:

 while(true );

Additionally as chris pointed out, calling setState too often in a loop might get you in trouble. 此外,正如克里斯指出的那样,在循环中调用setState过多可能会给您带来麻烦。

I don't think you want 我不想要你

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

as that queues 1000 timeouts without waiting for the previous timeout to finish . 因为这会排队1000个超时, 而无需等待上一个超时完成 And, additionally, is blocking. 并且,另外, 阻塞。

Here's a working codesandbox with what I think you're going for: https://codesandbox.io/s/2xy00529jp 这是一个正常工作的codeandbox,其中包含我认为您要使用的内容: https ://codesandbox.io/s/2xy00529jp

I took a little bit of a different approach - I'm keeping track of the timeouts and clearing them on stop - I don't think there's anything wrong with using a flag ( this.state.stop ), but I find my way a little cleaner. 我采取了一些不同的方法-我一直在跟踪超时并在stop清除它们-我认为使用标志( this.state.stop )没什么问题 ,但是我发现我的方式小清洁工。 Additionally, I'm using the callback for of this.setState - this is super important when doing a large number of sequential state updates where the new state value relies on the previous state value. 另外,我正在使用this.setState的回调-在进行大量顺序状态更新(新状态值依赖于先前状态值)时,这非常重要。 Take a look through this page for more info. 查看此页面以获取更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM