Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VUE 3.0 学习探索入门系列 - vue2.x/React/vue3.x 简单横评(4) #76

Open
sunmaobin opened this issue Apr 21, 2021 · 0 comments

Comments

@sunmaobin
Copy link
Owner

1 Vue 回顾

Vue.js 是 渐进式 的 JavaScript 框架。什么是 渐进式(Progressive) ?就是由浅入深,一步一步的,为什么 Evan You 说 Vue.js 是渐进式的框架呢?

  • Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合;
  • 现代化的工具链 以及各种 支持类库 结合使用时,Vue也完全能够为复杂的单页应用提供驱动

Vue.js 有啥特点呢?

  • 容易上手
  • 生态丰富完整
  • 文档清晰明了

当然,如果想更全面的了解 Vue,对比 React 和 Angular 等框架,可以看看这里的 横向对比

参考资料:cn.vuejs.org/v2/guide/

Vue2.x

Vue 自诞生开始,每一个大版本都在进步,相比 Vue1.x 而言,我们现在使用的 Vue 2.x 效果:

  • 更小,vue、vue-router 和 vuex 三个加一起,跟 Vue1.0 的核心库大小一样
  • 更快,基本是当前最快的框架,查看测试对比
  • 支持SSR 和 原生渲染

参考资料:juejin.im/entry/68449…

Vue3.x

相比 Vue2.x 而言,Vue3.x 的设计目标:

  • 更小
  • 更快
  • 加强 TypeScript 支持
  • 加强 API 设计一致性
  • 提高自身可维护性
  • 开放更多底层功能

参考资料:img.w3ctech.com/VueConf2019…

Evan You 为什么制定 Vue3.x 的这些目标呢?可能大家要先了解下 Vue2.x 的现状。

2 Vue 和 React 逃不掉的话题

2.1 Vue 和 React 哪个更好?

总体一个观点:众口难调!

总体一个原则:没有绝对好的框架,也没有绝对差的框架。每个人还是从各方面(自身技术能力、团队技术基础、上手成本、项目特点)考虑,选择一款适合自己的框架为好。

以下是 Evan You 对 Vue 和 React 对比的自我评价:

  • 如果多年以后要论历史地位,React 肯定是高于 Vue 的。事实上,我作为一个开发者,也是由衷地佩服 Jordan Walke, Sebastian Markbage 这样的,能从开发模式层面上提出突破性的新方向的人。
  • React 从一开始的定位就是提出 UI 开发的新思路;Vue 从一开始的定位就是尽可能的降低前端开发的门槛,让更多的人能够更快地上手开发

了解详情:www.zhihu.com/question/30…

One more thing

补充一点 Evan you 对 Vue 和 Angular 对比的自我评价:

了解详情:www.zhihu.com/question/40…

2.2 Vue 对于 Ts 的支持不够友好?

总体评价:Vue2.x 支持显然跟 React 和 Angular 是有差距的。

以下是 Evan You 对 Ts 的自我评价:

  • 现有的 API 和类型系统的结合存在缺陷,属于历史遗留,改新的 API 有个时机问题,所以 Vue3 出现了
  • TSX 类型支持好是因为 Ts 专门开了后门给做了支持,模版只要工具链到位一样可以做到
  • Vue 2 一开始内部实现就有类型系统,但是没想到 Flow 烂尾了,而 Ts 整个生态越做越好,这个属于就是押错宝了,只能说...Ts 真香!

了解详情:www.zhihu.com/question/31…

One more thing

另外 Evan You 当初为什么选择使用 Flow ,而不是直接上 Ts

看这里:www.zhihu.com/question/46…

2.3 Vue 更适合中小项目?

首先来看看知乎上的一个帖子,大家讨论的热火朝天:为什么react比vue更适合大型应用?

在我之前的面试中,当问到如何看待 React 和 Vue 这2个框架的时候,也有不少的人的回答是:Vue 适合中小项目,React 适合大型项目!

其实,在回答这个问题之前,大家首先得弄明白 “什么是中小项目?什么是大型项目?” 如果这个标准不统一,那大家争论是没有意义的。

就好比,什么是大前端?什么是前端工程化?这是我的理解

其实业界也没有太多定义,以下是个人观点(欢迎指正),大型项目满足其一就行:

  • 老板层面:项目经费超过 1000w
  • 经理层面:参与总人数超过 100人
  • 产品层面:核心需求总数超过 500个
  • 技术层面:代码行数超过 10w行

除此之外,都应该算作中小项目。

如果按照以上标准划分大中小型项目的话,大家平时有机会接触到的大项目有多少呢?

更何况,为了降低风险,除非无法拆分,不然一般公司里面大型项目也会被拆分成多个中小项目落地。所以,我要说的是,大家没必要从这个角度来划分一个前端框架,意义不大。

只是从人们的认知里面,一般认为的大型项目会出现以下问题,比如:

  • 前期考虑不周,后期简直无法维护
  • 人员能力参差不齐,代码质量很难保证
  • 人数众多,沟通交流成本太高
  • 各做各的,冗余代码多,冗余组件多
  • 接口设计太难,组件复用更难
  • 做两年可能就烂尾了,或者领导跑路了
  • 50%以上的功能都是产品异想天开,其实用户很少用!
  • 为了赶进度,1.0往往都做的跟翔一样
  • ...

好了,其实按我的理解,与其说是用项目大小来决定该选择哪个框架,不如从自身遇到问题出发衡量下适合自己的框架,因为以上问题不止大型项目的问题,所有项目都可能会遇到。

2.4 Vue3.x setup 和 React hooks 对比

  • 总的来说 setup 更符合 JS 的标准;
  • 对调用顺序不敏感,同时也可以有条件;
  • setup 仅被调用一次,并产生较小的GC压力;
  • 无需考虑 useCallback 几乎总是需要在哪儿防止内联处理程序导致子组件的过度渲染的问题;
  • 也无需考虑 useEffect 和 useMemo 产生的无用的变量,当用户使用了 watchers 或者 computed 的值,在自然失效以后

Vue setup 的思路借鉴了 React hooks 的灵感,同时也解决了 hooks 存在的上面的问题。

参考资料:vue-composition-api-rfc.netlify.com/#comparison…

2.5 个人观点 React 对比 Vue

简单对比下 React 和 Vue(个人理解和翻阅相关资料,欢迎批量指正,不引战!轻点喷!):

  1. React 更加拥抱 函数式编程 的思想,函数是一等公民;而 Vue2.x 更像是面向对象编程,AOP(切面)思想体现明显,比如:Options 一堆钩子的设计。到底哪个更好?随着 Vue3.x 的发布,答案就明了(下文会说)!
  2. React 一直是 Facebook 大公司维护;Vue 是个人作品,虽然到现在为止有 20人左右 的核心参与者,但是看 Github 提交记录(vuejs/vue工程),绝大多数代码还是 Evan You 提交维护(90%以上),其他人主要负责生态中的其他系统。这个会不会影响你选择使用哪个框架呢?我觉得至少在 Vue2.x 时代的时候,肯定有一些大的团队会优先考虑稳定性,毕竟历史上烂尾的例子太多了(近在眼前的 Flow 不就是么?偷笑)。
  3. 上面有提到 React 结合 Ts 开发,约束更强,规矩更多,对项目的风险把控较高;而 Vue2.x 对 Ts 支持天生较弱(上面已经仔细说了,没办法压错宝!),所以,对于使用 Ts 就回不去的人来说,简直无法忍受!但也不是不能用,只是有些弱(就个你用了Mac,就再回不到Windows一样)。
  4. 性能方面,大多数情况下 不分伯仲,更何况谁会傻到一个页面for循环几万条数据?或者组件嵌套10层以上呢?如果遇到我觉得需要优化产品,或者重构架构。
  5. 为什么对于 Vue3.x 大家都觉得越来越像 React?那是由于 Vue3.x 面对当前不足,借鉴了 React 的一些优点,弥补了自己的不足,比如:函数式编程、Ts 支持!所以,他们越来越像!
  6. 最后,如果说 Vue2.x 是 Evan you 基于各大门派独辟蹊径的一个轻量级、低门槛上手的框架的话,Vue3.x 更像是一个基于 React,将函数式编程这个自由发挥的编程思想重新包装,推出 Composition API,使其更有章法,更加规范的一个框架。

关于 Vue3.x

经过了上面各种对比,我们回过头来再看看 Vue3.x 改进:

3.1 Options API 到 Composition API 的转变

这其实是由完全面向对象OOP的思路,到函数式编程的思想转变。

只不过说起函数式编程大家看看文档可能都知道概念,无非业务逻辑都是一个个函数实现嘛!但是,真让你在项目里自由发挥写那么多函数的时候,你该怎么写?(这可能也是大家觉得 React 不太容易上手的以一个缘故吧,喜欢被 Vue 安排的明明白白!)

于是结合着 Vue2.x 里面的 Options API,将以前完全按照AOP模式的Options API,细粒度拆分成细小的函数,然后统一放到 setup 这一个入口函数中调用!鸡贼!佩服!

这样做的3个好处:

  1. 既保留了 Vue2.x 中各个函数的功能,做到兼容
  2. 同时以小的函数形式被调用,更加灵活,更好维护,更好 tree-shaking
  3. 最后还能将大家头痛的不知道如何函数式编程的痛点,安排明白一些(Composition API)

可谓:一石三鸟

下面以示例的形式来解释下这个概念。

比如 Vue2.x 时对于一个独立组件:

开始只有简单的鼠标处理逻辑。

export default {
    data() {
        return {
            x: 0,
            y: 0
        }
    },
    mounted() {
        window.addEventListener('mousemove', this.update)
    },
    methods: {
        update(e) {
            this.x = e.pageX
            this.y = e.pageY
        }
    },
    destroyed() {
        window.removeEventListener('mousemove', this.update)
    }
}
复制代码

以上会存在什么问题呢?举例来说明:

随着时间的推移,这个组件可能会发展成如下的模样!

export default {
    data() {
        return {
            x: 0,
            y: 0,
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            g: 0,
            h: 0,
            i: 0,
            j: 0,
            k: 0,
            l: 0,
            m: 0,
            n: 0 // 算了写不下去了。。。总之 data 可能会有很多
        }
    },
    mixins: [
        a,
        b,
        c,
        d,
        e,
        f // 算了,写不下去了,总之为了拆分代码,mixins 已经让我写到吐了
    ],
    mounted() {
        window.addEventListener('mousemove', this.update)
        
        // TODO 接下来可能会有一堆页面渲染完成的逻辑在这里哦
        
        // 这里是业务逻辑1
        // if / else if / else
        
        // 下面是业务逻辑2
        // while 
        
        // 哎呀所有的事情,都需要在页面渲染完去做呀,没办法
        // switch
        
        // 算了,写不下去了。。。
        // 跑路。。。
    },
    methods: {
        update(e) {
            this.x = e.pageX
            this.y = e.pageY
        },
        // 下面有一堆方法等着你哦
        method1() {
            // 预留着,方法只能放到 methods 对象下啊
        },
        method2() {
            // 张三的注释
            // 一堆逻辑
        },
        method3() {
            // ... 跑路了。。。
        }
    },
    destroyed() {
        window.removeEventListener('mousemove', this.update)
    }
}
复制代码

大家看出来上面的代码的问题了么?因为大家必须在 Vue 规定的条条框框里面写东西,所以,尤其初学者,会把一个简单的组件,写到简直无法直视的地步!

那你可能要说了,以上代码是有很多解决办法的呀,比如下面2种常见的优化方案:

1、将这个文件拆分成多个子组件或者模块

比如:如果按模块拆分,可以把 data 拆分成一个js文件,methods 拆分成一个 js 文件,等等。这么做只是相当于把一堆代码打散而已,代码连贯性、可维护性方面,变得更糟了。

再比如:拆分成多个子组件,每个子组件实现一块逻辑!(这是强拆!)大家拆分组件的原则,肯定不是基于代码量去拆的吧!所以,这会让业务模块,变得支离破碎,难以理解和维护。

2、使用 mixins 提取公共代码

mixins 解决的是公共的代码混入复用,如果只是一个组件过于庞大,你拆分到 mixins 多个文件中,有啥意义呢?跟上面的强拆有啥区别?

更何况,即便有复用的代码,如果一个文件中引入 10个以上的 mixin 文件,里面的 data 可能会覆盖,methods 可能会覆盖,你知道哪个生效了?template 使用的变量,你知道来自哪里?

对于上面的示例,Vue3.x 的解决办法

定义独立文件 mouse.js

这个文件就只处理鼠标事件!业务和代码逻辑都在一起,好理解,易于维护。

import { ref, onMounted, onUnmounted } from 'vue'

export function useMousePosition() {
  const x = ref(0)
  const y = ref(0)

  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })

  return { x, y }
}
复制代码

main.vue 引入文件

这里的代码量也变的很少,很清晰。

import { useMousePosition } from './mouse'

export default {
  setup() {
    const { x, y } = useMousePosition()
    // other logic...
    return { x, y }
  }
}
复制代码

示例参考:vue-composition-api-rfc.netlify.com/#logic-extr…

如果遇到不同的业务模块,就单独到独立文件或者模块处理,然后引入即可,比如:

(下面的逻辑如果在 vue2.x 中还真不太好处理!)

export default {
  setup () {
    // Network
    const { networkState } = useNetworkState()

    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)

    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()

    // Utils
    const { slicePath } = usePathUtils()

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath
    }
  }
}
复制代码

参考代码:vue-composition-api-rfc.netlify.com/#code-organ…

看了以上代码有啥感想?我自己的感受:

  • 如果代码量不大,组件比较小的情况下,我更喜欢 Vue2.x 的语法(被安排)。
  • 如果业务集中,组件复杂,我更喜欢 Vue3.x 的写法。好在至少目前得到的消息,Vue3.x 会大部分兼容 Vue2.x 的特性,赞!

3.2 更好的支持 Ts

Vue2.x 写法:

import { Component, Prop, Vue } from 'vue-property-decorator'

@Component
export default class HelloWorld extends Vue {
  @Prop() private message!: string;

  data (): object {
    // this.message
  }
}
复制代码

Vue3.x 写法:

import { defineComponent } from 'vue'
export default defineComponent({
  props: {
    message: String
  },
  setup(props, context) {
    // setup 中无法使用 this 关键词
    
    // props.message
    // context.attrs
    // context.slots
    // context.emit
  }
})
复制代码

对比下,至少写法上更简单,而且不用在使用那么多的 装饰器 了!

3.3 其他

再回过头来看看 Evan You 对 Vue3.x 的目标定义:

  • 更小
  • 更快
  • 加强 TypeScript 支持 上文已说明
  • 加强 API 设计一致性 上文已说明
  • 提高自身可维护性 上文已说明
  • 开放更多底层功能

更小

对比了 vue@3.0.0-alpha.8vue@2.6.11 这2个版本的未压缩版本的文件大小:

单纯从这2个独立的版本看,3.0还变大了!

所以,个人认为,真正要能变小,可能还是要放到工程化体系中,依赖编译器,比如:webpack,然后基于 3.0 这种函数式编程更好 tree shaking 的机制,最终打包编译后的效果而言。

更快

Vue3.x 以下重大变化:

  • 数据绑定策略由 Object.defineProperty() 换成了 new Proxy()
  • 重构了Virtual DOM
  • 更多编译时优化,如:Slot 默认编译为函数

参考地址:img.w3ctech.com/VueConf2019…

理论上性能上肯定要比之前好(至少 Proxy 就更高效一些),但是这个目前还不好验证,相信正式 Release 后续官方也会给出一些数据,同时圈内肯定也会有很多测试结果出炉。

开放更多底层功能

我觉得应该就是 API 更完善一些吧,比如:

Vue3.x 的生命周期新增了2个 Debug Hooks(用于调试的钩子函数):

  • onRenderTracked
  • onRenderTriggered

参考:vue-composition-api-rfc.netlify.com/api.html#li…

更多的等后面在仔细梳理。

(本文完)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
前端
Awaiting triage
Development

No branches or pull requests

1 participant