diff --git a/packages/editor/src/initService.ts b/packages/editor/src/initService.ts index 08728819..83d70b46 100644 --- a/packages/editor/src/initService.ts +++ b/packages/editor/src/initService.ts @@ -278,20 +278,21 @@ export const initServiceEvents = ( }); }; - const collectIdle = (nodes: MComponent[], deep: boolean, type?: DepTargetType) => - Promise.all( - nodes.map((node) => { - let pageId: Id | undefined; + const getPageIdByNode = (node: MComponent) => { + let pageId: Id | undefined; - if (isPage(node)) { - pageId = node.id; - } else { - const info = editorService.getNodeInfo(node.id); - pageId = info.page?.id; - } - return depService.collectIdle([node], { pageId }, deep, type); - }), - ); + if (isPage(node)) { + pageId = node.id; + } else { + const info = editorService.getNodeInfo(node.id); + pageId = info.page?.id; + } + + return pageId; + }; + + const collectIdle = (nodes: MComponent[], deep: boolean, type?: DepTargetType) => + Promise.all(nodes.map((node) => depService.collectIdle([node], { pageId: getPageIdByNode(node) }, deep, type))); watch( () => editorService.get('stage'), @@ -338,7 +339,8 @@ export const initServiceEvents = ( if (Array.isArray(value.items)) { depService.clearIdleTasks(); - collectIdle(value.items, true).then(() => { + + (typeof Worker === 'undefined' ? collectIdle(value.items, true) : depService.collectByWorker(value)).then(() => { updateStageNodes(value.items); }); } else { @@ -629,16 +631,12 @@ export const initServiceEvents = ( root.dataSourceDeps = {}; } root.dataSourceDeps[target.id] = target.deps; - } - - if (target.type === DepTargetType.DATA_SOURCE_COND) { + } else if (target.type === DepTargetType.DATA_SOURCE_COND) { if (!root.dataSourceCondDeps) { root.dataSourceCondDeps = {}; } root.dataSourceCondDeps[target.id] = target.deps; - } - - if (target.type === DepTargetType.DATA_SOURCE_METHOD) { + } else if (target.type === DepTargetType.DATA_SOURCE_METHOD) { if (!root.dataSourceMethodDeps) { root.dataSourceMethodDeps = {}; } diff --git a/packages/editor/src/services/dep.ts b/packages/editor/src/services/dep.ts index 5893db7e..364ab12d 100644 --- a/packages/editor/src/services/dep.ts +++ b/packages/editor/src/services/dep.ts @@ -17,12 +17,14 @@ */ import { reactive, shallowReactive } from 'vue'; import { throttle } from 'lodash-es'; +import serialize from 'serialize-javascript'; -import type { DepExtendedData, Id, MNode, Target, TargetNode } from '@tmagic/core'; -import { DepTargetType, Watcher } from '@tmagic/core'; +import type { DepData, DepExtendedData, Id, MApp, MNode, Target, TargetNode } from '@tmagic/core'; +import { DepTargetType, traverseTarget, Watcher } from '@tmagic/core'; import { isPage } from '@tmagic/utils'; -import { IdleTask } from '@editor/utils/idle-task'; +import { IdleTask } from '@editor/utils/dep/idle-task'; +import Work from '@editor/utils/dep/worker.ts?worker&inline'; import BaseService from './BaseService'; @@ -50,6 +52,8 @@ class Dep extends BaseService { private watcher = new Watcher({ initialTargets: reactive({}) }); + private waitingWorker?: Promise; + constructor() { super(); @@ -114,7 +118,11 @@ class Dep extends BaseService { this.emit('ds-collected', nodes, deep); } - public collectIdle(nodes: MNode[], depExtendedData: DepExtendedData = {}, deep = false, type?: DepTargetType) { + public async collectIdle(nodes: MNode[], depExtendedData: DepExtendedData = {}, deep = false, type?: DepTargetType) { + if (this.waitingWorker) { + await this.waitingWorker; + } + this.set('collecting', true); let startTask = false; this.watcher.collectByCallback(nodes, type, ({ node, target }) => { @@ -141,6 +149,48 @@ class Dep extends BaseService { }); } + public collectByWorker(dsl: MApp) { + this.set('collecting', true); + + const { promise, resolve: waitingResolve } = Promise.withResolvers(); + + this.waitingWorker = promise; + + return new Promise>>((resolve) => { + const worker = new Work(); + worker.postMessage({ + dsl: serialize(dsl), + }); + worker.onmessage = (e) => { + resolve(e.data); + }; + worker.onerror = () => { + resolve({}); + }; + }).then((depsData) => { + traverseTarget(this.watcher.getTargetsList(), (target) => { + if (depsData[target.type]?.[target.id]) { + target.deps = reactive(depsData[target.type][target.id]); + + if (target.type === DepTargetType.DATA_SOURCE && dsl.dataSourceDeps) { + dsl.dataSourceDeps[target.id] = target.deps; + } else if (target.type === DepTargetType.DATA_SOURCE_COND && dsl.dataSourceCondDeps) { + dsl.dataSourceCondDeps[target.id] = target.deps; + } else if (target.type === DepTargetType.DATA_SOURCE_METHOD) { + dsl.dataSourceMethodDeps[target.id] = target.deps; + } + } + }); + + this.set('collecting', false); + this.emit('collected', dsl.items, true); + this.emit('ds-collected', dsl.items, true); + waitingResolve(); + + return depsData; + }); + } + public collectNode(node: MNode, target: Target, depExtendedData: DepExtendedData = {}, deep = false) { // 先删除原有依赖,重新收集 if (isPage(node)) { diff --git a/packages/editor/src/utils/idle-task.ts b/packages/editor/src/utils/dep/idle-task.ts similarity index 100% rename from packages/editor/src/utils/idle-task.ts rename to packages/editor/src/utils/dep/idle-task.ts diff --git a/packages/editor/src/utils/dep/worker.ts b/packages/editor/src/utils/dep/worker.ts new file mode 100644 index 00000000..d7b4337c --- /dev/null +++ b/packages/editor/src/utils/dep/worker.ts @@ -0,0 +1,63 @@ +import { + createCodeBlockTarget, + createDataSourceCondTarget, + createDataSourceMethodTarget, + createDataSourceTarget, + type DepData, + DepTargetType, + type Id, + type MApp, + traverseTarget, + Watcher, +} from '@tmagic/core'; + +import { error } from '../logger'; + +onmessage = (e) => { + const watcher = new Watcher({ initialTargets: {} }); + + const { dsl } = e.data; + + try { + // eslint-disable-next-line no-eval + const mApp: MApp = eval(`(${dsl})`); + + if (!mApp) { + postMessage({}); + } + + if (mApp.codeBlocks) { + for (const [id, code] of Object.entries(mApp.codeBlocks)) { + watcher.addTarget(createCodeBlockTarget(id, code)); + } + } + + if (mApp.dataSources) { + for (const ds of mApp.dataSources) { + watcher.addTarget(createDataSourceTarget(ds, {})); + watcher.addTarget(createDataSourceMethodTarget(ds, {})); + watcher.addTarget(createDataSourceCondTarget(ds, {})); + } + } + + watcher.collectByCallback(mApp.items, undefined, ({ node, target }) => { + watcher.collectItem(node, target, { pageId: node.id }, true); + }); + + const data: Record> = { + [DepTargetType.DATA_SOURCE]: {}, + [DepTargetType.DATA_SOURCE_METHOD]: {}, + [DepTargetType.DATA_SOURCE_COND]: {}, + [DepTargetType.CODE_BLOCK]: {}, + }; + + traverseTarget(watcher.getTargetsList(), (target) => { + data[target.type][target.id] = target.deps; + }); + + postMessage(data); + } catch (e: any) { + error(e); + postMessage({}); + } +}; diff --git a/packages/editor/src/utils/index.ts b/packages/editor/src/utils/index.ts index 2dc45bb2..bca5a085 100644 --- a/packages/editor/src/utils/index.ts +++ b/packages/editor/src/utils/index.ts @@ -22,7 +22,7 @@ export * from './logger'; export * from './editor'; export * from './operator'; export * from './data-source'; -export * from './idle-task'; +export * from './dep/idle-task'; export * from './scroll-viewer'; export * from './tree'; export * from './undo-redo';