IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    从React Fiber到协程

    Kingfish404发表于 2021-08-30 00:00:00
    love 0

    Fiber是Facebook的React框架核心算法的2年重构的产物,Fiber reconciler。并且在React16中启用。

    这里笔者默认读者都了解过React和Vue中都有的虚拟Dom(vnode)概念,同时也对这类框架的更新原理,diff算法有一定的认知。

    简单来说,本文前置知识要求:

    • 前端基本知识,html,css,js
    • React
    • 虚拟dom/vnode
    • Diff算法

    Fiber

    听说React团队在实现Fiber过程中考虑使用协程来实现,但是由于不适合/工程量太大而没有最终使用。

    React在引入Fiber之前,由于其Diff算法需要递归去判断来对视图层做更新,就算实现了O(n)复杂度的Diff算法,但是由于其需要完成一次Diff才能更新视图层,所以导致当有递归层级非常深的组建树需要进行更新时,会产生用户感知非常明显的卡顿,这个问题就是Fiber解决的核心问题。

    前端各种技术最根本的目的都是为了提高用户体验

    React通过Fiber架构,让Reconcilation过程变成可被中断。'适时'地让出CPU执行权,通过这种方式,能够让浏览器及时地响应用户的交互,用户拥有了更好的体验,编译器也有机会进行编译优化(JIT)及进行热代码优化。

    实现Fiber的数据结构是链表,可以说,React升级到Fiber,就是一个数据结构课可能很常见做过的,递归转循环的过程。因为递归变成了循环,所以能够非常方便的回到顶层环境,找到上下文,对真实的dom节点进行更新。

    在绝大部分语言中,通过将程序的循环结构变成递归,减少了很多次的函数调用,可以极大的提高程序的效率。

    更多Fiber的概念,笔者可能讲的不如下方REF中讲的好,有兴趣可以直接前往查看。

    协程

    React的Fiber据笔者了解,并不是一个新的东西,而是有点类似参考了操作系统中时间分片,任务调度的思想进行设计的一个优化解决方案。当然前端当前许多的发展方向都是基于以往的系统,编程语言及后端所用到的的思想。

    Fiber也称协程。笔者第一次接触这个概念是在学习go以及python的时候,当然很多语言都有这样的一个机制。

    React Fiber的思想和协程的概念是契合的: React渲染的过程可以被中断,可以将控制权交回浏览器,让位给高优先级的任务,浏览器空闲后再恢复渲染。

    如果希望更深入的理解Fiber,那就最好对协程有所了解。

    协程是在线程基础上进一步的抽象细分,是单线程基础上的一种拓展。

    正好整理一下目前已有的运行程式:

    • 进程: 系统分配资源的最小单位
    • 线程: CPU时间片分配的最小单位
    • 协程: 在线程基础上的异步逻辑单位

    简单来说:一个进程可以有多个线程,一个线程占用一个cpu,一个线程可能有多个协程。

    关于协程,笔者感觉下面这个Python的例子更加直观:

    def consumer():
        r = ''
        while True:
            # 普通函数执行的过程中无法被中断和恢复,协程通过引入 async/await 或者 yield 等语法实现中断机制
    
            n = yield r     # 函数中断,等待收到信号r
    
            if not n:
                return
            print('[CONSUMER] Consuming %s...' % n)
            r = '200 OK'
    
    def produce(c):
        c.send(None)        # 发送一个信号给 r
        n = 0
        while n < 3:
            n = n + 1
            print('[PRODUCER] Producing %s...' % n)
            r = c.send(n)   # 发送一个信号给 r
            print('[PRODUCER] Consumer return: %s' % r)
        c.close()
    
    c = consumer()
    produce(c)
    # output:
    # [PRODUCER] Producing 1...
    # [CONSUMER] Consuming 1...
    # [PRODUCER] Consumer return: 200 OK
    # [PRODUCER] Producing 2...
    # [CONSUMER] Consuming 2...
    # [PRODUCER] Consumer return: 200 OK
    # [PRODUCER] Producing 3...
    # [CONSUMER] Consuming 3...
    # [PRODUCER] Consumer return: 200 OK
    

    看完协程,笔者其实想到了闭包这一概念,因为两者都保留了一个子函数的运行环境,都是单线程运行,可以被其他函数调用进入此环境。但是两者其实差别也很大,比如前者是能够进入函数运行的中间阶段,而后者是在一个函数的开头进入。

    最后

    站在巨人的肩膀上

    计算机领域有很多社区,其中有很多优秀的项目和资料,笔者受益颇多,也希望能够继续从其中汲取,并也参与进行贡献。

    本文只是简单的讲Fiber的思路和优点,同时对其设计思想的部分来源协程进行科普和对比,想深入了解请阅读下面不容错过的文章。

    最后更新于: 2021-09-05

    REF

    • 源码概览 - React
    • acdlite/react-fiber-architecture - Github
    • 【译】React Fiber 架构 · YAPN
    • React Fiber 原理介绍 - Segmentfault
    • 协程 - 廖雪峰的官方网站
    • 这可能是最通俗的 React Fiber(时间分片) 打开方式


沪ICP备19023445号-2号
友情链接