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 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进行扩展
|
||||
* 方法1:
|
||||
@ -74,8 +114,10 @@ const isError = (error: any): boolean => Object.prototype.toString.call(error) =
|
||||
export default class extends EventEmitter {
|
||||
private pluginOptionsList: Record<string, Function[]> = {};
|
||||
private middleware: Record<string, Function[]> = {};
|
||||
private taskList: (() => Promise<void>)[] = [];
|
||||
private doingTask = false;
|
||||
|
||||
constructor(methods: string[]) {
|
||||
constructor(methods: string[] = [], serialMethods: string[] = []) {
|
||||
super();
|
||||
|
||||
methods.forEach((propertyName: string) => {
|
||||
@ -93,32 +135,28 @@ export default class extends EventEmitter {
|
||||
const fn = compose(this.middleware[propertyName]);
|
||||
Object.defineProperty(scope, propertyName, {
|
||||
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) => {
|
||||
if (typeof beforeReturnValue[index] === 'undefined') return v;
|
||||
return beforeReturnValue[index];
|
||||
// 由于async await,所以会出现函数执行到await时让出线程,导致执行顺序出错,例如调用了select(1) -> update -> select(2),这个时候就有可能出现update了2;
|
||||
// 这里保证函数调用严格按顺序执行;
|
||||
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));
|
||||
|
||||
for (const afterMethod of this.pluginOptionsList[afterMethodName]) {
|
||||
returnValue = await afterMethod(...beforeArgs, returnValue);
|
||||
|
||||
if (isError(returnValue)) throw returnValue;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -135,4 +173,14 @@ export default class extends EventEmitter {
|
||||
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,21 +57,25 @@ class Editor extends BaseService {
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
'getLayout',
|
||||
'select',
|
||||
'add',
|
||||
'remove',
|
||||
'update',
|
||||
'sort',
|
||||
'copy',
|
||||
'paste',
|
||||
'alignCenter',
|
||||
'moveLayer',
|
||||
'undo',
|
||||
'redo',
|
||||
'highlight',
|
||||
]);
|
||||
super(
|
||||
[
|
||||
'getLayout',
|
||||
'select',
|
||||
'add',
|
||||
'remove',
|
||||
'update',
|
||||
'sort',
|
||||
'copy',
|
||||
'paste',
|
||||
'alignCenter',
|
||||
'moveLayer',
|
||||
'undo',
|
||||
'redo',
|
||||
'highlight',
|
||||
],
|
||||
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
||||
['select', 'update', 'moveLayer'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,8 +198,8 @@ class Editor extends BaseService {
|
||||
*/
|
||||
public highlight(config: MNode | Id): void {
|
||||
const { node } = this.selectedConfigExceptionHandler(config);
|
||||
const currentHighligtNode = this.get('highlightNode');
|
||||
if (currentHighligtNode === node) return;
|
||||
const currentHighlightNode = this.get('highlightNode');
|
||||
if (currentHighlightNode === node) return;
|
||||
this.set('highlightNode', node);
|
||||
}
|
||||
|
||||
@ -335,10 +339,9 @@ class Editor extends BaseService {
|
||||
|
||||
if (`${newConfig.id}` === `${this.get('node').id}`) {
|
||||
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) {
|
||||
this.set('page', newConfig);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user