fix(editor): 新增service方法串行调用问题,解决连续快速拖动导致更新节点错乱问题

This commit is contained in:
roymondchen 2022-04-07 14:47:19 +08:00 committed by jia000
parent 9746bab435
commit b8d352a885
2 changed files with 93 additions and 42 deletions

View File

@ -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]) { // 由于async await所以会出现函数执行到await时让出线程导致执行顺序出错例如调用了select(1) -> update -> select(2)这个时候就有可能出现update了2
let beforeReturnValue = (await beforeMethod(...beforeArgs)) || []; // 这里保证函数调用严格按顺序执行;
const promise = new Promise<any>((resolve, reject) => {
if (isError(beforeReturnValue)) throw beforeReturnValue; this.taskList.push(async () => {
try {
if (!Array.isArray(beforeReturnValue)) { const value = await doAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn);
beforeReturnValue = [beforeReturnValue]; resolve(value);
} } catch (e) {
reject(e);
beforeArgs = beforeArgs.map((v: any, index: number) => { }
if (typeof beforeReturnValue[index] === 'undefined') return v;
return beforeReturnValue[index];
}); });
});
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;
}
} }

View File

@ -57,21 +57,25 @@ class Editor extends BaseService {
}); });
constructor() { constructor() {
super([ super(
'getLayout', [
'select', 'getLayout',
'add', 'select',
'remove', 'add',
'update', 'remove',
'sort', 'update',
'copy', 'sort',
'paste', 'copy',
'alignCenter', 'paste',
'moveLayer', 'alignCenter',
'undo', 'moveLayer',
'redo', 'undo',
'highlight', 'redo',
]); '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,10 +339,9 @@ 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);
} }