文章 评论 浏览 28
对于 非concurrent 模式 答案 0023 屏幕显示 0 1 2 3
组件创建 屏幕显示 val 为 0
componentDidMount 执行注意:(对于前两次之所以都是0 , 并不是 因为 isBatchingUpdates 为 true, 而是还在处理渲染状态,(只有事件系统等触发的才会isBatchingUpdates设置为true)所谓的渲染状态 也就是源码 isRendering 是 true , 这个变量是 虚拟DOM构建过程以及commit过程中都会维持 true 的状态。)(1)第一个setState触发,创建一个 调度任务,此时 调度链表中有 初始化创建的调度任务和这一次的调度任务。这次调度的过期时间因为是 非concurrent,所以是 sync。将 {val: 1} 对象放入到调度的updateQueue中。此时并不会马上执行,因为 第一个创建的调度还没有结束 isRendering 还是true。所以不会进入渲染阶段,屏幕还是 0.(2)然后打印 0.(3)第二个setState触发,创建一个调度任务, 此时的调度链表中有三个调度任务,分别为 初始化的时候调度、第一次setSate、第二次setSate. 这次调度的过期时间因为是 非concurrent,所以是 sync。将 {val: 1} 对象放入到调度的updateQueue中。同理 isRendering 还是 true,屏幕显示还是0.(4) 然后打印0.(5)初始化结束开始,isRendering 设置成 false。第一个初始化调度从调度链表中清除,开始进入处理剩下调度任务过程, 然后由于两次的调度任务一致, 所以,优先级一样,先处理第一次的调度任务,由于 第一次 setState 与第二次 优先级都一样, 所以在 render 阶段 收集 更新的时候都被处理了。(6)屏幕显示 1(并不是 两次 setState 都会输出,而是由于过期时间都一样在 render 的收集更新的时候被处理调了)
setTime 执行(1)由于此时 isRendering 是false, 所以不会批量更新,而是第三个 setState 调用的时候,过期时间为 sync。 然后创建调度,然后直接进入更新。(2) 打印输出2. 屏幕显示 2(3)同理,第四个setState 同步执行(4)打印输出 3, 屏幕显示 3
对于 concurrent 模式 正常60hz刷新率情况下 答案 0011 屏幕显示 1 2
组件创建,进入调度执行,因为第一个创建的调度任务 肯定是在一帧空闲时间内执行的, 但是可能在 commit 阶段 检测到没有剩余时间了, 所以不会绘制到屏幕上。此时 isRendering 还是true
componentDidMount 执行(1)执行第一个 setState, 此时 isRendering 是 true,仅仅是创建 调度任务 过期时间是一个异步的时间戳。并不会执行。(2)打印出 0(3)执行第二个 setState, 此时 isRedndering是true, 也是不会执行, 仅仅市创建调度任务, 注意的是,这里的异步过期时间与第一次的相同(因为 都是在一个 rendering 中)。(4)打印出 0(5)此时调度到第二个setState 的 调度任务的时候, 调度时间早已经过期了,所以退化成 同步的方式直接执行,屏幕绘制出 1。
setTimeout 执行(1)第三个setState,进入到下一个时间循环的时候,在这之前可能执行了一次 state 变更,变成了1 所以 第三个创建调度任务的时候 val 可能是 2(只能说是可能, 因为不同的刷新率 和 组件大小都会影响了上一次的setState, 但是在目前实例仅仅有一个组件的情况下,state 肯定变成了 1 的因为必然执行了 render 过程)(2)打印出 1(也是可能值,只不过在 60hz 刷新率下 1 的概率最大)(3)第四个setState,创建调度任务,此调度任务放入队列,该过期时间可能与第三次的过期时间相同,因为异步计算时间都是在50ms 内的都作为一个过期时间。因为 两个过期时间一致, 所有中断了第三次的更新,进而更新第四次的。(4)打印出 1(5)屏幕显示 2
文章 0 评论 0
接受
对于 非concurrent 模式 答案 0023 屏幕显示 0 1 2 3
组件创建 屏幕显示 val 为 0
componentDidMount 执行
注意:(对于前两次之所以都是0 , 并不是 因为 isBatchingUpdates 为 true, 而是还在处理渲染状态,(只有事件系统等触发的才会isBatchingUpdates设置为true)所谓的渲染状态 也就是源码 isRendering 是 true , 这个变量是 虚拟DOM构建过程以及commit过程中都会维持 true 的状态。)
(1)第一个setState触发,创建一个 调度任务,此时 调度链表中有 初始化创建的调度任务和这一次的调度任务。这次调度的过期时间因为是 非concurrent,所以是 sync。将 {val: 1} 对象放入到调度的updateQueue中。此时并不会马上执行,因为 第一个创建的调度还没有结束 isRendering 还是true。所以不会进入渲染阶段,屏幕还是 0.
(2)然后打印 0.
(3)第二个setState触发,创建一个调度任务, 此时的调度链表中有三个调度任务,分别为 初始化的时候调度、第一次setSate、第二次setSate. 这次调度的过期时间因为是 非concurrent,所以是 sync。将 {val: 1} 对象放入到调度的updateQueue中。同理 isRendering 还是 true,屏幕显示还是0.
(4) 然后打印0.
(5)初始化结束开始,isRendering 设置成 false。第一个初始化调度从调度链表中清除,开始进入处理剩下调度任务过程, 然后由于两次的调度任务一致, 所以,优先级一样,先处理第一次的调度任务,由于 第一次 setState 与第二次 优先级都一样, 所以在 render 阶段 收集 更新的时候都被处理了。
(6)屏幕显示 1(并不是 两次 setState 都会输出,而是由于过期时间都一样在 render 的收集更新的时候被处理调了)
setTime 执行
(1)由于此时 isRendering 是false, 所以不会批量更新,而是第三个 setState 调用的时候,过期时间为 sync。 然后创建调度,然后直接进入更新。
(2) 打印输出2. 屏幕显示 2
(3)同理,第四个setState 同步执行
(4)打印输出 3, 屏幕显示 3
对于 concurrent 模式 正常60hz刷新率情况下 答案 0011 屏幕显示 1 2
组件创建,进入调度执行,因为第一个创建的调度任务 肯定是在一帧空闲时间内执行的, 但是可能在 commit 阶段 检测到没有剩余时间了, 所以不会绘制到屏幕上。此时 isRendering 还是true
componentDidMount 执行
(1)执行第一个 setState, 此时 isRendering 是 true,仅仅是创建 调度任务 过期时间是一个异步的时间戳。并不会执行。
(2)打印出 0
(3)执行第二个 setState, 此时 isRedndering是true, 也是不会执行, 仅仅市创建调度任务, 注意的是,这里的异步过期时间与第一次的相同(因为 都是在一个 rendering 中)。
(4)打印出 0
(5)此时调度到第二个setState 的 调度任务的时候, 调度时间早已经过期了,所以退化成 同步的方式直接执行,屏幕绘制出 1。
setTimeout 执行
(1)第三个setState,进入到下一个时间循环的时候,在这之前可能执行了一次 state 变更,变成了1 所以 第三个创建调度任务的时候 val 可能是 2(只能说是可能, 因为不同的刷新率 和 组件大小都会影响了上一次的setState, 但是在目前实例仅仅有一个组件的情况下,state 肯定变成了 1 的因为必然执行了 render 过程)
(2)打印出 1(也是可能值,只不过在 60hz 刷新率下 1 的概率最大)
(3)第四个setState,创建调度任务,此调度任务放入队列,该过期时间可能与第三次的过期时间相同,因为异步计算时间都是在50ms 内的都作为一个过期时间。因为 两个过期时间一致, 所有中断了第三次的更新,进而更新第四次的。
(4)打印出 1
(5)屏幕显示 2
第 19 题:React setState 笔试题,下面的代码输出什么?