Dictionary 高效的Redux缩减器,避免不必要的对象拷贝
我想我的问题也可以概括为 是否有一种惯用的ES6方法:Dictionary 高效的Redux缩减器,避免不必要的对象拷贝,dictionary,functional-programming,ecmascript-6,functor,redux,Dictionary,Functional Programming,Ecmascript 6,Functor,Redux,我想我的问题也可以概括为 是否有一种惯用的ES6方法: array.map(identity)==array array.filter(i=>true)==array {obj…,attr:obj.attr}==obj 我知道,它在ES6中并没有像这样实现,但是否有一些可能的语法我遗漏了,或者有一些简单的帮助函数使这些属性为真而不诉诸于不可变的库 我使用Babel和新的JS特性,以及不可变的JS对象 我想知道如何使我的还原程序更有效,并生成更少不必要的对象副本 我对lib(Mori/Immut
array.map(identity)==array
array.filter(i=>true)==array
{obj…,attr:obj.attr}==obj
我知道,它在ES6中并没有像这样实现,但是否有一些可能的语法我遗漏了,或者有一些简单的帮助函数使这些属性为真而不诉诸于不可变的库
我使用Babel和新的JS特性,以及不可变的JS对象 我想知道如何使我的还原程序更有效,并生成更少不必要的对象副本 我对lib(Mori/ImmutableJS)解决方案不感兴趣 我有一个管理分页列表的缩减器
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
之类的事件时,my reducer都会返回一个新状态,返回一个新的页面数组,即使数组中的任何项都没有实际更新。这会创建不必要的对象复制和GC
我不想过早地对此进行优化,也不想在我的应用程序中引入一个不可变的库,但我想知道是否有任何惯用的ES6方法来解决这个问题?不可变的数据结构,如immutable.js和Mori使用了一个巧妙的技巧来避免一直重新创建整个结构 该策略相当简单:当您更新一个属性时,深入到该属性,对其进行更改,并从该节点到根节点重写所有属性 假设您希望在以下状态下将属性
c
更改为4
:
const state1 = {
a: {
b: {
c: 1
},
d: [2, 3, 4],
e: 'Hello'
}
}
第一步是将c
更新为4
。之后,您需要创建
b
的新对象(因为c
已更改)a
的新对象(因为b
已更改)a
已更改)*
表示该对象已被重新创建)
请注意,d
和e
如何未被触摸
现在,您可以验证工作是否正常:
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
您可能注意到state1
和state2
之间共享d
和e
您可以使用类似的策略共享您所在州的信息,而无需一直重新创建一个全新的州
关于你最初的问题:
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!
它是这样工作的,因为方法就是这样定义的。ES6在这里没有提供替代方案或任何有帮助的东西。您是否过度关注这里的优化?您是否尝试过对减速器进行基准测试,以确定这是否需要太长时间,或者进行内存分析,看看这是否真的是一个内存问题?我认为有一个库可以做到这一点。当我专注于优化我的应用程序时,我可能会这样做:)我知道不可变结构和身份比较是如何工作的,我正在寻找一种方法来解决所描述的用例,而不是解释为什么
{obj…,attr:obj.attr}!==obj
。我重写了我的问题以使它更清楚
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!