Skip to content

Commit 88e40a7

Browse files
committed
perf: throttle queue + subscribe simplification
1 parent d0b5fea commit 88e40a7

File tree

8 files changed

+208
-150
lines changed

8 files changed

+208
-150
lines changed

packages/app-backend-core/src/component.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { stringify, BridgeEvents, parse, SharedData } from '@vue-devtools/shared-utils'
1+
import { stringify, BridgeEvents, parse, SharedData, createThrottleQueue } from '@vue-devtools/shared-utils'
22
import { AppRecord, BackendContext, BuiltinBackendFeature } from '@vue-devtools/app-backend-api'
33
import { getAppRecord } from './app'
44
import { App, ComponentInstance, EditStatePayload } from '@vue/devtools-api'
@@ -131,11 +131,16 @@ export async function refreshComponentTreeSearch (ctx: BackendContext) {
131131
await sendComponentTreeData(ctx.currentAppRecord, '_root', ctx.currentAppRecord.componentFilter, null, false, ctx)
132132
}
133133

134-
export async function sendComponentUpdateTracking (instanceId: string, ctx: BackendContext) {
134+
const updateTrackingQueue = createThrottleQueue(500)
135+
136+
export function sendComponentUpdateTracking (instanceId: string, time: number, ctx: BackendContext) {
135137
if (!instanceId) return
136-
const payload = {
137-
instanceId,
138-
time: Date.now(), // Use normal date
139-
}
140-
ctx.bridge.send(BridgeEvents.TO_FRONT_COMPONENT_UPDATED, payload)
138+
139+
updateTrackingQueue.add(instanceId, () => {
140+
const payload = {
141+
instanceId,
142+
time,
143+
}
144+
ctx.bridge.send(BridgeEvents.TO_FRONT_COMPONENT_UPDATED, payload)
145+
})
141146
}

packages/app-backend-core/src/index.ts

Lines changed: 136 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
SharedData,
2020
isBrowser,
2121
raf,
22+
createThrottleQueue,
2223
} from '@vue-devtools/shared-utils'
2324
import debounce from 'lodash/debounce'
2425
import throttle from 'lodash/throttle'
@@ -118,27 +119,13 @@ async function connect () {
118119

119120
// Components
120121

121-
const sendComponentUpdate = throttle(async (appRecord: AppRecord, id: string) => {
122-
try {
123-
// Update component inspector
124-
if (ctx.currentInspectedComponentId === id) {
125-
await sendSelectedComponentData(appRecord, ctx.currentInspectedComponentId, ctx)
126-
}
127-
128-
// Update tree (tags)
129-
if (isSubscribed(BridgeSubscriptions.COMPONENT_TREE, sub => sub.payload.instanceId === id)) {
130-
await sendComponentTreeData(appRecord, id, appRecord.componentFilter, 0, false, ctx)
131-
}
132-
} catch (e) {
133-
if (SharedData.debugInfo) {
134-
console.error(e)
135-
}
136-
}
137-
}, 100)
122+
const throttleQueue = createThrottleQueue(500)
138123

139124
hook.on(HookEvents.COMPONENT_UPDATED, async (app, uid, parentUid, component) => {
140125
try {
141126
if (!app || (typeof uid !== 'number' && !uid) || !component) return
127+
const now = Date.now()
128+
142129
let id: string
143130
let appRecord: AppRecord
144131
if (app && uid != null) {
@@ -149,15 +136,40 @@ async function connect () {
149136
appRecord = ctx.currentAppRecord
150137
}
151138

152-
if (SharedData.trackUpdates) {
153-
await sendComponentUpdateTracking(id, ctx)
154-
}
139+
throttleQueue.add(`update:${id}`, async () => {
140+
try {
141+
const time = performance.now()
155142

156-
if (SharedData.flashUpdates) {
157-
await flashComponent(component, appRecord.backend)
158-
}
143+
const trackUpdateNow = performance.now()
144+
if (SharedData.trackUpdates) {
145+
sendComponentUpdateTracking(id, now, ctx)
146+
}
147+
const trackUpdateTime = performance.now() - trackUpdateNow
148+
149+
const flashNow = performance.now()
150+
if (SharedData.flashUpdates) {
151+
await flashComponent(component, appRecord.backend)
152+
}
153+
const flashTime = performance.now() - flashNow
159154

160-
await sendComponentUpdate(appRecord, id)
155+
const sendUpdateNow = performance.now()
156+
// Update component inspector
157+
if (ctx.currentInspectedComponentId === id) {
158+
await sendSelectedComponentData(appRecord, ctx.currentInspectedComponentId, ctx)
159+
}
160+
161+
// Update tree (tags)
162+
if (isSubscribed(BridgeSubscriptions.COMPONENT_TREE, id)) {
163+
await sendComponentTreeData(appRecord, id, appRecord.componentFilter, 0, false, ctx)
164+
}
165+
const sendUpdateTime = performance.now() - sendUpdateNow
166+
// console.log('COMPONENT_UPDATED', id, Math.round(performance.now() - time) + 'ms', { trackUpdateTime, flashTime, sendUpdateTime, updatedData: ctx.currentInspectedComponentId === id })
167+
} catch (e) {
168+
if (SharedData.debugInfo) {
169+
console.error(e)
170+
}
171+
}
172+
})
161173
} catch (e) {
162174
if (SharedData.debugInfo) {
163175
console.error(e)
@@ -168,51 +180,63 @@ async function connect () {
168180
hook.on(HookEvents.COMPONENT_ADDED, async (app, uid, parentUid, component) => {
169181
try {
170182
if (!app || (typeof uid !== 'number' && !uid) || !component) return
183+
const now = Date.now()
171184
const id = await getComponentId(app, uid, component, ctx)
172-
const appRecord = await getAppRecord(app, ctx)
173-
if (component) {
174-
if (component.__VUE_DEVTOOLS_UID__ == null) {
175-
component.__VUE_DEVTOOLS_UID__ = id
176-
}
177-
if (appRecord?.instanceMap) {
178-
if (!appRecord.instanceMap.has(id)) {
179-
appRecord.instanceMap.set(id, component)
180-
}
181-
}
182-
}
183185

184-
if (parentUid != null && appRecord?.instanceMap) {
185-
const parentInstances = await appRecord.backend.api.walkComponentParents(component)
186-
if (parentInstances.length) {
187-
// Check two parents level to update `hasChildren
188-
for (let i = 0; i < parentInstances.length; i++) {
189-
const parentId = await getComponentId(app, parentUid, parentInstances[i], ctx)
190-
if (i < 2 && isSubscribed(BridgeSubscriptions.COMPONENT_TREE, sub => sub.payload.instanceId === parentId)) {
191-
raf(() => {
192-
sendComponentTreeData(appRecord, parentId, appRecord.componentFilter, null, false, ctx)
193-
})
186+
throttleQueue.add(`add:${id}`, async () => {
187+
try {
188+
const time = performance.now()
189+
const appRecord = await getAppRecord(app, ctx)
190+
if (component) {
191+
if (component.__VUE_DEVTOOLS_UID__ == null) {
192+
component.__VUE_DEVTOOLS_UID__ = id
193+
}
194+
if (appRecord?.instanceMap) {
195+
if (!appRecord.instanceMap.has(id)) {
196+
appRecord.instanceMap.set(id, component)
197+
}
194198
}
199+
}
200+
201+
if (parentUid != null && appRecord?.instanceMap) {
202+
const parentInstances = await appRecord.backend.api.walkComponentParents(component)
203+
if (parentInstances.length) {
204+
// Check two parents level to update `hasChildren
205+
for (let i = 0; i < parentInstances.length; i++) {
206+
const parentId = await getComponentId(app, parentUid, parentInstances[i], ctx)
207+
if (i < 2 && isSubscribed(BridgeSubscriptions.COMPONENT_TREE, parentId)) {
208+
raf(() => {
209+
sendComponentTreeData(appRecord, parentId, appRecord.componentFilter, null, false, ctx)
210+
})
211+
}
195212

196-
if (SharedData.trackUpdates) {
197-
await sendComponentUpdateTracking(parentId, ctx)
213+
if (SharedData.trackUpdates) {
214+
sendComponentUpdateTracking(parentId, now, ctx)
215+
}
216+
}
198217
}
199218
}
200-
}
201-
}
202219

203-
if (ctx.currentInspectedComponentId === id) {
204-
await sendSelectedComponentData(appRecord, id, ctx)
205-
}
220+
if (ctx.currentInspectedComponentId === id) {
221+
await sendSelectedComponentData(appRecord, id, ctx)
222+
}
206223

207-
if (SharedData.trackUpdates) {
208-
await sendComponentUpdateTracking(id, ctx)
209-
}
224+
if (SharedData.trackUpdates) {
225+
sendComponentUpdateTracking(id, now, ctx)
226+
}
210227

211-
if (SharedData.flashUpdates) {
212-
await flashComponent(component, appRecord.backend)
213-
}
228+
if (SharedData.flashUpdates) {
229+
await flashComponent(component, appRecord.backend)
230+
}
214231

215-
await refreshComponentTreeSearch(ctx)
232+
await refreshComponentTreeSearch(ctx)
233+
// console.log('COMPONENT_ADDED', id, Math.round(performance.now() - time) + 'ms')
234+
} catch (e) {
235+
if (SharedData.debugInfo) {
236+
console.error(e)
237+
}
238+
}
239+
})
216240
} catch (e) {
217241
if (SharedData.debugInfo) {
218242
console.error(e)
@@ -223,39 +247,50 @@ async function connect () {
223247
hook.on(HookEvents.COMPONENT_REMOVED, async (app, uid, parentUid, component) => {
224248
try {
225249
if (!app || (typeof uid !== 'number' && !uid) || !component) return
226-
const appRecord = await getAppRecord(app, ctx)
227-
if (parentUid != null && appRecord) {
228-
const parentInstances = await appRecord.backend.api.walkComponentParents(component)
229-
if (parentInstances.length) {
230-
const parentId = await getComponentId(app, parentUid, parentInstances[0], ctx)
231-
if (isSubscribed(BridgeSubscriptions.COMPONENT_TREE, sub => sub.payload.instanceId === parentId)) {
232-
raf(async () => {
233-
try {
234-
const appRecord = await getAppRecord(app, ctx)
235-
236-
if (appRecord) {
237-
sendComponentTreeData(appRecord, parentId, appRecord.componentFilter, null, false, ctx)
238-
}
239-
} catch (e) {
240-
if (SharedData.debugInfo) {
241-
console.error(e)
242-
}
250+
const id = await getComponentId(app, uid, component, ctx)
251+
252+
throttleQueue.add(`remove:${id}`, async () => {
253+
try {
254+
const time = performance.now()
255+
const appRecord = await getAppRecord(app, ctx)
256+
if (parentUid != null && appRecord) {
257+
const parentInstances = await appRecord.backend.api.walkComponentParents(component)
258+
if (parentInstances.length) {
259+
const parentId = await getComponentId(app, parentUid, parentInstances[0], ctx)
260+
if (isSubscribed(BridgeSubscriptions.COMPONENT_TREE, parentId)) {
261+
raf(async () => {
262+
try {
263+
const appRecord = await getAppRecord(app, ctx)
264+
265+
if (appRecord) {
266+
sendComponentTreeData(appRecord, parentId, appRecord.componentFilter, null, false, ctx)
267+
}
268+
} catch (e) {
269+
if (SharedData.debugInfo) {
270+
console.error(e)
271+
}
272+
}
273+
})
243274
}
244-
})
275+
}
245276
}
246-
}
247-
}
248277

249-
const id = await getComponentId(app, uid, component, ctx)
250-
if (isSubscribed(BridgeSubscriptions.SELECTED_COMPONENT_DATA, sub => sub.payload.instanceId === id)) {
251-
await sendEmptyComponentData(id, ctx)
252-
}
278+
if (isSubscribed(BridgeSubscriptions.SELECTED_COMPONENT_DATA, id)) {
279+
await sendEmptyComponentData(id, ctx)
280+
}
253281

254-
if (appRecord) {
255-
appRecord.instanceMap.delete(id)
256-
}
282+
if (appRecord) {
283+
appRecord.instanceMap.delete(id)
284+
}
257285

258-
await refreshComponentTreeSearch(ctx)
286+
await refreshComponentTreeSearch(ctx)
287+
// console.log('COMPONENT_REMOVED', id, Math.round(performance.now() - time) + 'ms')
288+
} catch (e) {
289+
if (SharedData.debugInfo) {
290+
console.error(e)
291+
}
292+
}
293+
})
259294
} catch (e) {
260295
if (SharedData.debugInfo) {
261296
console.error(e)
@@ -264,7 +299,7 @@ async function connect () {
264299
})
265300

266301
hook.on(HookEvents.TRACK_UPDATE, (id, ctx) => {
267-
sendComponentUpdateTracking(id, ctx)
302+
sendComponentUpdateTracking(id, Date.now(), ctx)
268303
})
269304

270305
hook.on(HookEvents.FLASH_UPDATE, (instance, backend) => {
@@ -273,22 +308,22 @@ async function connect () {
273308

274309
// Component perf
275310

276-
hook.on(HookEvents.PERFORMANCE_START, async (app, uid, vm, type, time) => {
277-
await performanceMarkStart(app, uid, vm, type, time, ctx)
311+
hook.on(HookEvents.PERFORMANCE_START, (app, uid, vm, type, time) => {
312+
performanceMarkStart(app, uid, vm, type, time, ctx)
278313
})
279314

280-
hook.on(HookEvents.PERFORMANCE_END, async (app, uid, vm, type, time) => {
281-
await performanceMarkEnd(app, uid, vm, type, time, ctx)
315+
hook.on(HookEvents.PERFORMANCE_END, (app, uid, vm, type, time) => {
316+
performanceMarkEnd(app, uid, vm, type, time, ctx)
282317
})
283318

284319
// Highlighter
285320

286-
hook.on(HookEvents.COMPONENT_HIGHLIGHT, async instanceId => {
287-
await highlight(ctx.currentAppRecord.instanceMap.get(instanceId), ctx.currentAppRecord.backend, ctx)
321+
hook.on(HookEvents.COMPONENT_HIGHLIGHT, instanceId => {
322+
highlight(ctx.currentAppRecord.instanceMap.get(instanceId), ctx.currentAppRecord.backend, ctx)
288323
})
289324

290-
hook.on(HookEvents.COMPONENT_UNHIGHLIGHT, async () => {
291-
await unHighlight()
325+
hook.on(HookEvents.COMPONENT_UNHIGHLIGHT, () => {
326+
unHighlight()
292327
})
293328

294329
// Timeline
@@ -409,12 +444,12 @@ async function connect () {
409444
function connectBridge () {
410445
// Subscriptions
411446

412-
ctx.bridge.on(BridgeEvents.TO_BACK_SUBSCRIBE, ({ type, payload }) => {
413-
subscribe(type, payload)
447+
ctx.bridge.on(BridgeEvents.TO_BACK_SUBSCRIBE, ({ type, key }) => {
448+
subscribe(type, key)
414449
})
415450

416-
ctx.bridge.on(BridgeEvents.TO_BACK_UNSUBSCRIBE, ({ type, payload }) => {
417-
unsubscribe(type, payload)
451+
ctx.bridge.on(BridgeEvents.TO_BACK_UNSUBSCRIBE, ({ type, key }) => {
452+
unsubscribe(type, key)
418453
})
419454

420455
// Tabs
@@ -450,7 +485,7 @@ function connectBridge () {
450485

451486
ctx.bridge.on(BridgeEvents.TO_BACK_COMPONENT_TREE, async ({ instanceId, filter, recursively }) => {
452487
ctx.currentAppRecord.componentFilter = filter
453-
subscribe(BridgeSubscriptions.COMPONENT_TREE, { instanceId })
488+
subscribe(BridgeSubscriptions.COMPONENT_TREE, instanceId)
454489
await sendComponentTreeData(ctx.currentAppRecord, instanceId, filter, null, recursively, ctx)
455490
})
456491

packages/app-backend-core/src/perf.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export async function performanceMarkEnd (
145145
if (change) {
146146
// Update component tree
147147
const id = await getComponentId(app, uid, instance, ctx)
148-
if (isSubscribed(BridgeSubscriptions.COMPONENT_TREE, sub => sub.payload.instanceId === id)) {
148+
if (isSubscribed(BridgeSubscriptions.COMPONENT_TREE, id)) {
149149
raf(() => {
150150
sendComponentTreeData(appRecord, id, ctx.currentAppRecord.componentFilter, null, false, ctx)
151151
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy