mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-19 22:58:15 +00:00
refactor(perf): 将修改节点属性时间优化到毫秒级
This commit is contained in:
parent
c5a8e79318
commit
61f1c2ec5a
@ -398,11 +398,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
this.setupContextMenu();
|
this.setupContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
postEvent(eventName: string, data: any) {
|
postEvent(eventName: string, ...data: any[]) {
|
||||||
this.emitter.emit(eventName, data);
|
this.emitter.emit(eventName, ...data);
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivityEvent(cb: (activity: ActivityData) => void) {
|
onActivityEvent(cb: (activity: ActivityData, ctx?: any) => void) {
|
||||||
this.emitter.on('activity', cb);
|
this.emitter.on('activity', cb);
|
||||||
return () => {
|
return () => {
|
||||||
this.emitter.off('activity', cb);
|
this.emitter.off('activity', cb);
|
||||||
@ -439,7 +439,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
newValue,
|
newValue,
|
||||||
prop,
|
prop,
|
||||||
},
|
},
|
||||||
});
|
}, { doc: this.currentDocument });
|
||||||
});
|
});
|
||||||
// editor.on('node.add', ({ node }) => {
|
// editor.on('node.add', ({ node }) => {
|
||||||
// console.log('add node', node);
|
// console.log('add node', node);
|
||||||
|
|||||||
@ -18,8 +18,7 @@ import {
|
|||||||
getProjectUtils,
|
getProjectUtils,
|
||||||
applyActivities,
|
applyActivities,
|
||||||
} from '@ali/lowcode-utils';
|
} from '@ali/lowcode-utils';
|
||||||
|
import { RootSchema, ComponentSchema, TransformStage, NodeSchema, ActivityType, ActivityData } from '@ali/lowcode-types';
|
||||||
import { RootSchema, ComponentSchema, TransformStage, NodeSchema, ActivityData } from '@ali/lowcode-types';
|
|
||||||
// just use types
|
// just use types
|
||||||
import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel } from '@ali/lowcode-designer';
|
import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel } from '@ali/lowcode-designer';
|
||||||
import LowCodeRenderer from '@ali/lowcode-react-renderer';
|
import LowCodeRenderer from '@ali/lowcode-react-renderer';
|
||||||
@ -27,9 +26,11 @@ import { createMemoryHistory, MemoryHistory } from 'history';
|
|||||||
import Slot from './builtin-components/slot';
|
import Slot from './builtin-components/slot';
|
||||||
import Leaf from './builtin-components/leaf';
|
import Leaf from './builtin-components/leaf';
|
||||||
import { withQueryParams, parseQuery } from './utils/url';
|
import { withQueryParams, parseQuery } from './utils/url';
|
||||||
|
import { supportsQuickPropSetting, getUppermostPropKey, setInstancesProp } from './utils/misc';
|
||||||
const loader = new AssetLoader();
|
const loader = new AssetLoader();
|
||||||
|
const FULL_RENDER_THRESHOLD = 1000;
|
||||||
export class DocumentInstance {
|
export class DocumentInstance {
|
||||||
private instancesMap = new Map<string, ReactInstance[]>();
|
public instancesMap = new Map<string, ReactInstance[]>();
|
||||||
|
|
||||||
@obx.ref private _schema?: RootSchema;
|
@obx.ref private _schema?: RootSchema;
|
||||||
@computed get schema(): any {
|
@computed get schema(): any {
|
||||||
@ -39,12 +40,33 @@ export class DocumentInstance {
|
|||||||
private disposeFunctions: Array<() => void> = [];
|
private disposeFunctions: Array<() => void> = [];
|
||||||
|
|
||||||
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
|
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
|
||||||
this.disposeFunctions.push(host.autorun(() => {
|
const documentExportDisposer = host.autorun(() => {
|
||||||
this._schema = document.export(TransformStage.Render);
|
this._schema = document.export(TransformStage.Render);
|
||||||
}));
|
});
|
||||||
this.disposeFunctions.push(host.onActivityEvent((data: ActivityData) => {
|
this.disposeFunctions.push(documentExportDisposer);
|
||||||
if (host.mutedActivityEvent) return;
|
let tid: NodeJS.Timeout;
|
||||||
|
this.disposeFunctions.push(host.onActivityEvent((data: ActivityData, ctx: any) => {
|
||||||
|
if (host.mutedActivityEvent || (ctx && ctx.doc !== this.document)) return;
|
||||||
|
|
||||||
|
if (tid) clearTimeout(tid);
|
||||||
|
// 临时关闭全量计算 schema 的逻辑,在增量计算结束后,来一次全量计算
|
||||||
|
documentExportDisposer.$obx.sleep();
|
||||||
|
if (data.type === ActivityType.MODIFIED) {
|
||||||
|
// 对于修改场景,优先判断是否能走「快捷设置」逻辑
|
||||||
|
if (supportsQuickPropSetting(data, this)) {
|
||||||
|
setInstancesProp(data, this);
|
||||||
|
} else {
|
||||||
this._schema = applyActivities(this._schema!, data);
|
this._schema = applyActivities(this._schema!, data);
|
||||||
|
}
|
||||||
|
} else if (data.type === ActivityType.ADDED) {
|
||||||
|
// FIXME: 待补充 节点增加 逻辑
|
||||||
|
} else if (data.type === ActivityType.DELETED) {
|
||||||
|
// FIXME: 待补充 节点删除 逻辑
|
||||||
|
} else if (data.type === ActivityType.COMPOSITE) {
|
||||||
|
// FIXME: 待补充逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
tid = setTimeout(() => documentExportDisposer.$obx.wakeup(true), FULL_RENDER_THRESHOLD);
|
||||||
// TODO: 调试增量模式,打开以下代码
|
// TODO: 调试增量模式,打开以下代码
|
||||||
// this._deltaData = data;
|
// this._deltaData = data;
|
||||||
// this._deltaMode = true;
|
// this._deltaMode = true;
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
import { ReactInstance } from 'react';
|
||||||
|
import { ActivityData } from '@ali/lowcode-types';
|
||||||
|
import { DocumentInstance } from '../renderer';
|
||||||
|
|
||||||
interface UtilsMetadata {
|
interface UtilsMetadata {
|
||||||
name: string;
|
name: string;
|
||||||
npm: {
|
npm: {
|
||||||
@ -24,3 +28,68 @@ export function getProjectUtils(librayMap: LibrayMap, utilsMetadata: UtilsMetada
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最靠近 Props / PropStash 的 prop 实例
|
||||||
|
* @param prop
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getUppermostPropKey(prop: any): string {
|
||||||
|
let curProp = prop;
|
||||||
|
while (curProp.parent.constructor.name !== 'Props' && curProp.parent.constructor.name !== 'PropStash') {
|
||||||
|
curProp = curProp.parent;
|
||||||
|
}
|
||||||
|
return curProp.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function haveForceUpdate(instances: any[]): boolean {
|
||||||
|
return instances.every(inst => 'forceUpdate' in inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持快捷属性值设值
|
||||||
|
* @param data
|
||||||
|
* @param doc
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function supportsQuickPropSetting(data: ActivityData, doc: DocumentInstance) {
|
||||||
|
const { payload } = data;
|
||||||
|
const { schema, prop } = payload;
|
||||||
|
const nodeId = schema.id!;
|
||||||
|
// const key = data.payload.prop.key;
|
||||||
|
const instances = doc.instancesMap.get(nodeId);
|
||||||
|
const uppermostPropKey = getUppermostPropKey(prop);
|
||||||
|
|
||||||
|
return (
|
||||||
|
nodeId &&
|
||||||
|
Array.isArray(instances) &&
|
||||||
|
instances.length > 0 &&
|
||||||
|
haveForceUpdate(instances) &&
|
||||||
|
uppermostPropKey &&
|
||||||
|
!uppermostPropKey.startsWith('___')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置属性值
|
||||||
|
* @param data
|
||||||
|
* @param doc
|
||||||
|
*/
|
||||||
|
export function setInstancesProp(data: ActivityData, doc: DocumentInstance) {
|
||||||
|
const { payload } = data;
|
||||||
|
const { schema, prop, newValue } = payload;
|
||||||
|
const nodeId = schema.id!;
|
||||||
|
const instances = doc.instancesMap.get(nodeId)!;
|
||||||
|
const propKey = getUppermostPropKey(prop);
|
||||||
|
let value = (schema.props as any)[propKey];
|
||||||
|
// 当 prop 是在 PropStash 中产生时,该 prop 需要在下一个 obx 的时钟周期才能挂载到相应位置,
|
||||||
|
// 而 schema 是同步 export 得到的,此时 schema 中还没有对应的值,所以直接取 newValue
|
||||||
|
if (prop.parent.constructor.name === 'PropStash') {
|
||||||
|
value = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.forEach((inst: any) => {
|
||||||
|
inst.props[propKey] = value;
|
||||||
|
inst.forceUpdate();
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -63,6 +63,7 @@ const pages = Object.assign(project, {
|
|||||||
item.methods = {};
|
item.methods = {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
project.load(
|
project.load(
|
||||||
{
|
{
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
@ -73,7 +74,6 @@ const pages = Object.assign(project, {
|
|||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: 根本原因是 PropStash 导致的,在页面节点初始化结束后,hideModalNodes 导致了第一次变化
|
// FIXME: 根本原因是 PropStash 导致的,在页面节点初始化结束后,hideModalNodes 导致了第一次变化
|
||||||
// 这样可以避免页面加载之后就被标记为 isModified
|
// 这样可以避免页面加载之后就被标记为 isModified
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user