ITPub博客

首页 > IT职业 > IT职场 > 从零开始实现一个React(四):异步的setState

从零开始实现一个React(四):异步的setState

IT职场 作者:jinxiaoliang 时间:2021-09-09 09:11:42 0 删除 编辑
上一篇文章中,我们实现了diff算法,性能有非常大的改进。但是文章末尾也指出了一个问题:按照目前的实现,每次调用setState都会触发更新,如果组件内执行这样一段代码:
for ( let i = 0; i 

那么执行这段代码会导致这个组件被重新渲染100次,这对性能是一个非常大的负担。

第二篇文章中对setState的实现:
setState( stateChange ) {
    Object.assign( this.state, stateChange );
    renderComponent( this );
}

这种实现,每次调用setState都会更新state并马上渲染一次。

阮一峰的这篇文章,这里就不再赘述了。

我们可以利用事件队列,让flush在所有同步任务后执行

function enqueueSetState( stateChange, component ) {
    // 如果queue的长度是0,也就是在上次flush执行之后第一次往队列里添加
    if ( queue.length === 0 ) {
        defer( flush );
    }
    queue.push( {
        stateChange,
        component
    } );
    if ( !renderQueue.some( item => item === component ) ) {
        renderQueue.push( component );
    }
}

定义defer方法,利用刚才题目中出现的Promise.resolve

function defer( fn ) {
    return Promise.resolve().then( fn );
}

这样在一次“事件循环“中,最多只会执行一次flush了,在这个“事件循环”中,所有的setState都会被合并,并只渲染一次组件。

别的延迟执行方法

除了用Promise.resolve().then( fn ),我们也可以用上文中提到的setTimeout( fn, 0 ),setTimeout的时间也可以是别的值,例如16毫秒。

16毫秒的间隔在一秒内大概可以执行60次,也就是60帧,人眼每秒只能捕获60幅画面

另外也可以用requestAnimationFrame或者requestIdleCallback

function defer( fn ) {
    return requestAnimationFrame( fn );
}

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3996/viewspace-2800299/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-10-17

  • 博文量
    73
  • 访问量
    534