3

我想我的问题也可以归结为类似高效Redux的减速,避免不必要的对象副本

是否有地道的ES6办法有:

array.map(identity) === array

array.filter(i => true) === array

{obj..., attr: obj.attr} === obj

我知道,它没有像ES6那样实现,但是有一些我可能缺少的语法或简单的帮助函数使这些属性成为true而不诉诸于不可变的lib吗?


我使用Babel和新的JS功能,具有不可变的js对象。

我想知道如何让我减速更有效率和产生更少的不必要的对象副本

我没有兴趣在一个lib(森/ ImmutableJS)解决方案。

我有一个reducer管理分页列表。

pages属性实际上是一个Array[Array[item]]

这里是我的减速器:

const initialState = { 
    isLoading: false, 
    pages: [], 
    allStamplesLoaded: false 
}; 

function reducer(state = initialState, event) { 

    switch (event.name) { 

    case Names.STAMPLE_DELETED: 
     return { 
     ...state, 
     pages: removeStampleFromPages(state.pages,event.data.stampleId) 
     }; 

    case Names.STAMPLE_UPDATED: 
     return { 
     ...state, 
     pages: updateStampleInPages(state.pages,event.data.apiStample) 
     }; 

    case Names.STAMPLE_PAGES_CLEANED: 
     return { 
     ...initialState, 
     }; 

    case Names.STAMPLE_PAGE_REQUESTED: 
     return { 
     ...state, 
     isLoading: true 
     }; 

    case Names.STAMPLE_PAGE_LOADED: 
     const {stamplePage,isLastPage} = event.data; 
     return { 
     ...state, 
     isLoading: false, 
     pages: [...state.pages, stamplePage], 
     isLastPage: isLastPage 
     }; 

    case Names.STAMPLE_PAGE_ERROR: 
     return { 
     ...state, 
     isLoading: false 
     }; 

    default: 
     return state; 
    } 
} 

我也有这些辅助功能:

function removeStampleFromPages(pages,deletedStampleId) { 
    return pages.map(page => { 
    return page.filter(apiStample => apiStample != deletedStampleId) 
    }) 
} 
function updateStampleInPages(pages,newApiStample) { 
    return pages.map(page => { 
    return updateStampleInPage(page,newApiStample); 
    }) 
} 
function updateStampleInPage(page,newApiStample) { 
    return page.map(apiStample => { 
    if (apiStample.id === newApiStample.id) { 
     return newApiStample; 
    } 
    else { 
     return apiStample; 
    } 
    }) 
} 

正如你可以看到,每次一个事件,如STAMPLE_UPDATED被解雇,然后我的reducer总是返回一个新的状态和一个新的页面数组,即使数组中的项目没有实际更新。这会造成不必要的对象复制和GC。

我不婉过早优化这个也不在我的应用程序引入不可变的库,但我想知道是否有任何地道ES6的方式来解决这个问题?

+1

它以这种方式工作,因为这就是如何定义方法。 ES6不提供替代或任何有用的帮助。 –

+0

您可能过度关注优化吗?你是否尝试过对你的减速器进行基准测试,看看这个过程是否需要很长时间,或者完成内存分析以确定这是否真的是内存问题? – markerikson

+0

我认为这是一个图书馆的利基,完全是这样。 –

回答

1

不可变的数据结构,例如Immutable.js和森使用一个聪明的办法来避免重新创建整个结构的所有时间。

的策略是相当简单:当你更新属性钻到财产,改变它,从这个节点,直到根重新包装全部财产。

让我们假设你想在下面的状态属性c更改为4

const state1 = { 
    a: { 
    b: { 
     c: 1 
    }, 
    d: [2, 3, 4], 
    e: 'Hello' 
    } 
} 

的第一步是更新c4。之后,你需要创建

  1. 一个新的对象为b(因为c改变)
  2. 一个新的对象a(因为b改变)
  3. 和新对象的状态(因为a改变)。

你的新的状态看起来像这样(一*靠近一个物体是指该对象已被重新创建)

const state2 = *{ 
    a: *{ 
    b: *{ 
     c: 4 
    }, 
    d: [2, 3, 4], 
    e: 'Hello' 
    } 
} 

注意如何de没有被感动。

现在,您可以验证一切是否正常工作:

state1 === state2 // false 
state1.a === state2.a // false 
state1.a.b === state2.a.b //false 
state1.d === state2.d // true 
state1.e === state2.e // true 

你可能会注意到,destate1state2之间共享。

您可以使用类似的策略在您的状态下共享信息,而无需重新创建全新的状态。

至于你最初的问题:

array.map(identity) !== array 
array.filter(i => true) !== array 
{obj..., attr: obj.attr} !== obj 

答案很简单。

当创建数组或对象时,Javascript VM在内部为该对象分配一个标识符。标识符是增量式的,所以没有两个数组/对象是相同的。

当您对数组或对象执行身份检查时,只会检查内部标识符是否匹配。

a = [] // internal identifier 1 
[] // internal identifier to 2 
b = [] // internal identifier 3 
a === b // id 1 === id 3 is FALSE! 
a === a // id 1 === id 1 is TRUE! 
+0

我知道如何不可变的结构和身份比较工作我正在寻找一种方法来解决所描述的用例,而不是解释为什么'{obj。 ..,attr:obj.attr}!== obj'。我重写了我的问题,使其更清楚 –

相关问题