mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-06 03:57:56 +08:00
fix(editor): 新增service方法串行调用问题,解决连续快速拖动导致更新节点错乱问题
This commit is contained in:
parent
9746bab435
commit
b8d352a885
@ -24,6 +24,46 @@ const methodName = (prefix: string, name: string) => `${prefix}${name[0].toUpper
|
|||||||
|
|
||||||
const isError = (error: any): boolean => Object.prototype.toString.call(error) === '[object Error]';
|
const isError = (error: any): boolean => Object.prototype.toString.call(error) === '[object Error]';
|
||||||
|
|
||||||
|
const doAction = async (
|
||||||
|
args: any[],
|
||||||
|
scope: any,
|
||||||
|
sourceMethod: any,
|
||||||
|
beforeMethodName: string,
|
||||||
|
afterMethodName: string,
|
||||||
|
fn: (args: any[], next?: Function | undefined) => Promise<void>,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
let beforeArgs = args;
|
||||||
|
|
||||||
|
for (const beforeMethod of scope.pluginOptionsList[beforeMethodName]) {
|
||||||
|
let beforeReturnValue = (await beforeMethod(...beforeArgs)) || [];
|
||||||
|
|
||||||
|
if (isError(beforeReturnValue)) throw beforeReturnValue;
|
||||||
|
|
||||||
|
if (!Array.isArray(beforeReturnValue)) {
|
||||||
|
beforeReturnValue = [beforeReturnValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeArgs = beforeArgs.map((v: any, index: number) => {
|
||||||
|
if (typeof beforeReturnValue[index] === 'undefined') return v;
|
||||||
|
return beforeReturnValue[index];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let returnValue: any = await fn(beforeArgs, sourceMethod.bind(scope));
|
||||||
|
|
||||||
|
for (const afterMethod of scope.pluginOptionsList[afterMethodName]) {
|
||||||
|
returnValue = await afterMethod(...beforeArgs, returnValue);
|
||||||
|
|
||||||
|
if (isError(returnValue)) throw returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提供两种方式对Class进行扩展
|
* 提供两种方式对Class进行扩展
|
||||||
* 方法1:
|
* 方法1:
|
||||||
@ -74,8 +114,10 @@ const isError = (error: any): boolean => Object.prototype.toString.call(error) =
|
|||||||
export default class extends EventEmitter {
|
export default class extends EventEmitter {
|
||||||
private pluginOptionsList: Record<string, Function[]> = {};
|
private pluginOptionsList: Record<string, Function[]> = {};
|
||||||
private middleware: Record<string, Function[]> = {};
|
private middleware: Record<string, Function[]> = {};
|
||||||
|
private taskList: (() => Promise<void>)[] = [];
|
||||||
|
private doingTask = false;
|
||||||
|
|
||||||
constructor(methods: string[]) {
|
constructor(methods: string[] = [], serialMethods: string[] = []) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
methods.forEach((propertyName: string) => {
|
methods.forEach((propertyName: string) => {
|
||||||
@ -93,32 +135,28 @@ export default class extends EventEmitter {
|
|||||||
const fn = compose(this.middleware[propertyName]);
|
const fn = compose(this.middleware[propertyName]);
|
||||||
Object.defineProperty(scope, propertyName, {
|
Object.defineProperty(scope, propertyName, {
|
||||||
value: async (...args: any[]) => {
|
value: async (...args: any[]) => {
|
||||||
let beforeArgs = args;
|
if (!serialMethods.includes(propertyName)) {
|
||||||
|
return doAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn);
|
||||||
for (const beforeMethod of this.pluginOptionsList[beforeMethodName]) {
|
|
||||||
let beforeReturnValue = (await beforeMethod(...beforeArgs)) || [];
|
|
||||||
|
|
||||||
if (isError(beforeReturnValue)) throw beforeReturnValue;
|
|
||||||
|
|
||||||
if (!Array.isArray(beforeReturnValue)) {
|
|
||||||
beforeReturnValue = [beforeReturnValue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeArgs = beforeArgs.map((v: any, index: number) => {
|
// 由于async await,所以会出现函数执行到await时让出线程,导致执行顺序出错,例如调用了select(1) -> update -> select(2),这个时候就有可能出现update了2;
|
||||||
if (typeof beforeReturnValue[index] === 'undefined') return v;
|
// 这里保证函数调用严格按顺序执行;
|
||||||
return beforeReturnValue[index];
|
const promise = new Promise<any>((resolve, reject) => {
|
||||||
|
this.taskList.push(async () => {
|
||||||
|
try {
|
||||||
|
const value = await doAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn);
|
||||||
|
resolve(value);
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.doingTask) {
|
||||||
|
this.doTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
let returnValue = await fn(beforeArgs, sourceMethod.bind(scope));
|
return promise;
|
||||||
|
|
||||||
for (const afterMethod of this.pluginOptionsList[afterMethodName]) {
|
|
||||||
returnValue = await afterMethod(...beforeArgs, returnValue);
|
|
||||||
|
|
||||||
if (isError(returnValue)) throw returnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnValue;
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -135,4 +173,14 @@ export default class extends EventEmitter {
|
|||||||
if (typeof method === 'function') this.pluginOptionsList[methodName].push(method);
|
if (typeof method === 'function') this.pluginOptionsList[methodName].push(method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async doTask() {
|
||||||
|
this.doingTask = true;
|
||||||
|
let task = this.taskList.shift();
|
||||||
|
while (task) {
|
||||||
|
await task();
|
||||||
|
task = this.taskList.shift();
|
||||||
|
}
|
||||||
|
this.doingTask = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,8 @@ class Editor extends BaseService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super(
|
||||||
|
[
|
||||||
'getLayout',
|
'getLayout',
|
||||||
'select',
|
'select',
|
||||||
'add',
|
'add',
|
||||||
@ -71,7 +72,10 @@ class Editor extends BaseService {
|
|||||||
'undo',
|
'undo',
|
||||||
'redo',
|
'redo',
|
||||||
'highlight',
|
'highlight',
|
||||||
]);
|
],
|
||||||
|
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
||||||
|
['select', 'update', 'moveLayer'],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,8 +198,8 @@ class Editor extends BaseService {
|
|||||||
*/
|
*/
|
||||||
public highlight(config: MNode | Id): void {
|
public highlight(config: MNode | Id): void {
|
||||||
const { node } = this.selectedConfigExceptionHandler(config);
|
const { node } = this.selectedConfigExceptionHandler(config);
|
||||||
const currentHighligtNode = this.get('highlightNode');
|
const currentHighlightNode = this.get('highlightNode');
|
||||||
if (currentHighligtNode === node) return;
|
if (currentHighlightNode === node) return;
|
||||||
this.set('highlightNode', node);
|
this.set('highlightNode', node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,9 +339,8 @@ class Editor extends BaseService {
|
|||||||
|
|
||||||
if (`${newConfig.id}` === `${this.get('node').id}`) {
|
if (`${newConfig.id}` === `${this.get('node').id}`) {
|
||||||
this.set('node', newConfig);
|
this.set('node', newConfig);
|
||||||
}
|
|
||||||
|
|
||||||
this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
|
this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
|
||||||
|
}
|
||||||
|
|
||||||
if (newConfig.type === NodeType.PAGE) {
|
if (newConfig.type === NodeType.PAGE) {
|
||||||
this.set('page', newConfig);
|
this.set('page', newConfig);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user