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
演示如下

我们看到 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);演示:
