653 字
3 分钟
时间分片

海量数据优化-时间分片#

时间分片的概念,就是一次性渲染大量数据,初始化的时候会出现卡顿等现象。我们必须要明白的一个道理,js执行永远要比dom渲染快的多。 ,所以对于大量的数据,一次性渲染,容易造成卡顿,卡死的情况。我们先来看一下例子

./Content.tsx

import { Button } from 'choerodon-ui';
import Icon from 'choerodon-ui/lib/icon/Icon';
import { map } from 'lodash';
import { observer } from 'mobx-react-lite';
import React, { useEffect, useRef, useState } from 'react';
import './index.less';
import { useDemos } from './stores';
const Demos = () => {
const {
mainStore,
} = useDemos();
const {
lists,
setLists,
} = mainStore;
useEffect(() => {
}, []);
function add() {
setLists(new Array(40000).fill(0));
}
function reset() {
setLists([]);
}
return (
<div className="demos">
<div>
<Button funcType="raised" type="primary" onClick={add}>add +</Button>
<Button funcType="raised" type="primary" onClick={reset}>reset</Button>
{
map(lists, (item:number, i:number) => (
<div className="demos-item" key={i}>
{`item-${i}`}
<Icon type="close" />
</div>
))
}
</div>
</div>
);
};
export default observer(Demos);

./stores/index.tsx

/* eslint-disable max-len */
import React, {
createContext, useCallback, useContext, useMemo,
} from 'react';
import { DataSet } from 'choerodon-ui/pro';
import { injectIntl } from 'react-intl';
import { inject } from 'mobx-react';
import useStore from './useStore';
interface ContextProps {
}
const Store = createContext({} as ContextProps);
export function useDemos() {
return useContext(Store);
}
export const StoreProvider = injectIntl(inject('AppState')((props: any) => {
const {
children,
intl: { formatMessage },
AppState: { currentMenuType: { projectId } },
} = props;
const mainStore = useStore();
const value = {
...props,
formatMessage,
projectId,
mainStore,
};
return (
<Store.Provider value={value}>
{children}
</Store.Provider>
);
}));

./stores/useStore.tsx

import { useLocalStore } from 'mobx-react-lite';
export default function useStore() {
return useLocalStore(() => ({
lists: [],
setLists(value:any) {
this.lists = value;
},
}));
}
export type StoreProps = ReturnType<typeof useStore>;

./index.tsx

import React from 'react';
import { StoreProvider } from './stores';
import Content from './Content';
const Index = (props: any) => (
<StoreProvider {...props}>
<Content />
</StoreProvider>
);
export default Index;

./index.less

.demos {
&-item {
border: 1px solid #0fc2e2;
background-color: #4adcf0;
color: #fff;
border-radius: 4px;
height: 50px;
width: 400px;
text-align: center;
font-size: 20px;
line-height: 50px;
& + & {
margin-top: 10px;
}
}
}

最主要的代码就是Content.tsx

演示如下

gif1

我们看到 40000 个 简单列表渲染了,将近5秒的时间。为了解决一次性加载大量数据的问题。我们引出了时间分片的概念,就是用setTimeout把任务分割,分成若干次来渲染。一共40000个数据,我们可以每次渲染100个, 分次400渲染。(这里用的是window.requestAnimationFrame())

import { Button } from 'choerodon-ui';
import Icon from 'choerodon-ui/lib/icon/Icon';
import { map } from 'lodash';
import { observer } from 'mobx-react-lite';
import React, { useEffect, useRef, useState } from 'react';
import './index.less';
import { useDemos } from './stores';
const Demos = () => {
const {
mainStore,
} = useDemos();
const {
lists,
setLists,
} = mainStore;
useEffect(() => {
}, []);
function handleSlice(list:number[], times:number) {
if (times === 400) return;
window.requestAnimationFrame(() => {
const newLists = list.slice(times, (times + 1) * 10);
setLists(lists.concat(newLists));
handleSlice(list, times + 1);
});
}
function add() {
handleSlice(new Array(4000).fill(0), 0);
}
function reset() {
setLists([]);
}
return (
<div className="demos">
<div>
<Button funcType="raised" type="primary" onClick={add}>add +</Button>
<Button funcType="raised" type="primary" onClick={reset}>reset</Button>
{
map(lists, (item:number, i:number) => (
<div className="demos-item" key={i}>
{`item-${i}`}
<Icon type="close" />
</div>
))
}
</div>
</div>
);
};
export default observer(Demos);

演示:

gif2

时间分片
https://nollieleo.github.io/posts/时间分片/
作者
翁先森
发布于
2020-12-28
许可协议
CC BY-NC-SA 4.0