V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
jahnsli
V2EX  ›  Vue.js

在 vue3 中, computed 计算属性性能问题

  •  
  •   jahnsli · Nov 5, 2022 · 3284 views
    This topic created in 1272 days ago, the information mentioned may be changed or developed.

    在下面的例子中,使用 vue3 的计算属性,我们应该将“computed”放在最外层还是单独对数据进行“computed”?哪个表现更好?

    const arr = computed(()=>[
      {options:cpuData.map((item)=>({...item,name:'tom'}))},
      {options:disData.map((item)=>({...item,name:'jerry'}))},
      {options:memoryData.map((item)=>({...item,name:'oh'}))},
      {options:testData.map((item)=>({...item,name:'test'}))},
      {options:[{name:'test'},{name:'test2'}]},
      {options:[{name:'test'},{name:'test2'}]},
      {options:[{name:'test'},{name:'test2'}]},
      {options:[{name:'test'},{name:'test2'}]},
    ])
    
    const arr = [
      {options:computed(()=>cpuData.map((item)=>({...item,name:'tom'}))),
      {options:computed(()=>disData.map((item)=>({...item,name:'tom'}))),
      {options:computed(()=>memoryData.map((item)=>({...item,name:'tom'}))),
      {options:computed(()=>testData.map((item)=>({...item,name:'tom'}))),
      {options:[{name:'test'},{name:'test2'}]},
      {options:[{name:'test'},{name:'test2'}]},
      {options:[{name:'test'},{name:'test2'}]},
      {options:[{name:'test'},{name:'test2'}]},
    ]
    
    
    23 replies    2022-11-18 17:48:46 +08:00
    vivipure
        1
    vivipure  
       Nov 6, 2022
    直觉第二种,但是写还是写第一种,没啥必要。
    wu67
        2
    wu67  
       Nov 6, 2022
    // 我一般这么写
    const temp = computed(() => [
    { options: cpuData.map(item => ({ ...item, name: 'tom' })) },
    { options: disData.map(item => ({ ...item, name: 'jerry' })) },
    { options: memoryData.map(item => ({ ...item, name: 'oh' })) },
    { options: testData.map(item => ({ ...item, name: 'test' })) },
    ])

    const constantData = [
    { options: [{ name: 'test' }, { name: 'test2' }] },
    { options: [{ name: 'test' }, { name: 'test2' }] },
    { options: [{ name: 'test' }, { name: 'test2' }] },
    { options: [{ name: 'test' }, { name: 'test2' }] },
    ]

    const result = computed(() => {
    return temp.concat(constantData)
    })
    wu67
        3
    wu67  
       Nov 6, 2022
    一般情况下, 纯展示的页面, 前端不需要考虑性能问题.

    但是当你的数据量到达某种程度之后, 就需要考虑空间换时间了, 例如:
    1. 你的一维数组的行数到达了千量级, 动不动就是几千行的数据
    2. 你的数据需要对 2 维数组进行处理, 例如 2~6 千行, 每行里面还有 3 4 百列的
    3. 3 维或者更复杂的玩意...

    到了这种地步之后才需要考虑是否需要优化. 可能实际情况会有所不同, 不能纯纯的靠空间换时间, 因为可能占用内存过高, 浏览器本身卡了, 不是数据便利的卡...
    zcf0508
        4
    zcf0508  
       Nov 6, 2022 via Android   ❤️ 1
    一,第二种的 arr 不是响应式的
    二,如果你不需要 arr 变更触发响应式的话,那第二种只会在读取 computed 的 index 才会触发响应式,其他的不会触发响应式,理论上性能更好
    三,就这几行数据应该不会有什么性能的差别
    Finnn
        5
    Finnn  
       Nov 6, 2022
    其实你第一种应该是无效的?
    因为 computed 并不能自动深度响应对象内部值的变化
    chenjiangui998
        6
    chenjiangui998  
       Nov 7, 2022
    @Finnn computed 默认就是深度响应的
    xintianyou
        7
    xintianyou  
       Nov 7, 2022
    @Finnn 你记错了吧,vue2 的 watch 才是默认不会深度响应
    Finnn
        8
    Finnn  
       Nov 12, 2022
    @xintianyou 只是题主的 computed 返回的数据结构是新构建的, 不存在监听已有引用类型, 如果 computed 一个对象内部的变化自然是不行的
    chenjiangui998
        10
    chenjiangui998  
       Nov 15, 2022
    @Finnn 你这个例子不正说明了 computed 是深度响应的吗, 如果不是, push 对象界面根本不会响应
    chenjiangui998
        11
    chenjiangui998  
       Nov 15, 2022   ❤️ 1
    @Finnn 而且直接 return author.books.map(() => '1'), log 也会多次执行
    Finnn
        12
    Finnn  
       Nov 15, 2022   ❤️ 1
    @chenjiangui998 你可以打开控制台呢, 看看 computed 了没有
    Finnn
        13
    Finnn  
       Nov 15, 2022
    @chenjiangui998 你这例子可差远了, 完全不是一个概念
    Finnn
        15
    Finnn  
       Nov 17, 2022
    @mizuhashi computed 并不会勤快到自动响应引用类型内部的未观察属性的变化, 既不合理也没有意义
    mizuhashi
        16
    mizuhashi  
       Nov 17, 2022 via iPhone
    @Finnn 我覺得這個說法不對,computed 會觀察所有「用到的」的屬性,但本身不一定會總是重復運行,在保證返回結果正確的情況下。你的例子裏沒有重復執行,但是返回的結果是正確的,我的例子裏如果不重復執行就不能確定結果正確,所以就重復執行了
    Finnn
        17
    Finnn  
       Nov 17, 2022
    @mizuhashi 因为你监控了 books.length, 一个变化的基本类型, 上面 return author.books.map(() => '1') 的同样是监控了 books 的每一个值的变化
    Finnn
        18
    Finnn  
       Nov 17, 2022
    @mizuhashi 你这说法更不对,怎么会不能确定结果的正确性.
    computed 之所以响应是因为其回调内部的所有监控值变化了才会执行, 直接响应一个对象自然是不会深度检查内部的各个值的变化的
    mizuhashi
        19
    mizuhashi  
       Nov 17, 2022
    @Finnn 「深度檢查內部各個值」的具體標準是什麼?如果引用了.length ,那麼 books 的元素變化會導致 length 變化,所以 computed 也重復執行了,這在我看來應該算深度檢查了內部值的。如果只是引用了.books ,這個 computed 關心的就僅僅是 books 返回的數組的引用,由於這個引用沒變,所以 computed 不會重新執行。

    如果要證明「 computed 不會監視深度的數組內容變化」,那麼應該構造這麼一個 computed ,其監視了並使用了數組的內容,但是當數組改變的時候,這個 computed 沒有觸發。如果只是.books ,並沒有使用數組的內容,而使用了數組內容的例子(如.books.length ),computed 是有重新觸發的,所以還需要一個有效的反例才能證明原命題。
    Finnn
        20
    Finnn  
       Nov 18, 2022
    Finnn
        21
    Finnn  
       Nov 18, 2022
    @mizuhashi 我认为你理解的深度并不是 vue 概念上的 watch 意义的深度,watch 的深度是自动响应引用类型内部所有值的变化的,computed 首先是惰性的,然后是只响应回调函数内所有声明监控的基本类型的变化, 就像 watch/computed:“author.books[3].length” 一样直达某个对象内部的一个基本类型的变化,这不是 vue 意义上的深度
    mizuhashi
        22
    mizuhashi  
       Nov 18, 2022
    @Finnn 我大概理解你說的了,你的深度的意思是當內容改變的時候總是會觸發副作用( computed 函數體),從這個定義來說的話 computed 並不是深度的。不過 computed 應該本身不是設計來觸發副作用的,只要它返回的 ref 可以保證響應到正確的數據就行,你最新的例子裏 publishedBooksMessage 也響應到正確的數據了,所以我覺得如果 OP 的 computed 裏面沒有副作用,那麼這個函數會不會重新運行應該是無所謂的
    Finnn
        23
    Finnn  
       Nov 18, 2022   ❤️ 1
    @mizuhashi 是的, 我在 #8 说明了, 因为 OP 的计算值返回的是新构造的数据结构, 不存在监控不到要 map 的数组, 当然这个数组变化的项目也必须是基本类型
    computed 不产生也不应该产生副作用
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   832 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 49ms · UTC 21:54 · PVG 05:54 · LAX 14:54 · JFK 17:54
    ♥ Do have faith in what you're doing.