perf(app): pause cached tab background work
This commit is contained in:
parent
abb214c620
commit
b0856e51bc
|
|
@ -1032,7 +1032,7 @@ onUnmounted(() => {
|
|||
@set-default-database="setActiveDatabaseAsDefault"
|
||||
@clear-default-database="clearActiveDefaultDatabase"
|
||||
/>
|
||||
<KeepAlive :max="20">
|
||||
<KeepAlive :max="8">
|
||||
<ContentArea
|
||||
ref="contentAreaRef"
|
||||
:key="activeTab.id"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, watch, shallowRef, computed } from "vue";
|
||||
import { ref, onMounted, onBeforeUnmount, onActivated, onDeactivated, watch, shallowRef, computed } from "vue";
|
||||
import { Play, Copy, TextSelect } from "lucide-vue-next";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import type { CompletionContext } from "@codemirror/autocomplete";
|
||||
|
|
@ -192,6 +192,8 @@ let setSqlDiagnosticsEffect: import("@codemirror/state").StateEffectType<SqlSema
|
|||
let semanticDiagnostics: SqlSemanticDiagnostic[] = [];
|
||||
let semanticDiagnosticTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let semanticDiagnosticRunId = 0;
|
||||
let editorIsActive = true;
|
||||
let tableReferenceDropListenerRegistered = false;
|
||||
|
||||
function editorThemeAppearance() {
|
||||
return isDark.value ? "dark" : "light";
|
||||
|
|
@ -724,6 +726,7 @@ async function refreshSemanticDiagnostics() {
|
|||
}
|
||||
|
||||
function scheduleSemanticDiagnostics(delay = 500) {
|
||||
if (!editorIsActive) return;
|
||||
if (semanticDiagnosticTimer) clearTimeout(semanticDiagnosticTimer);
|
||||
semanticDiagnosticTimer = setTimeout(() => {
|
||||
semanticDiagnosticTimer = null;
|
||||
|
|
@ -809,6 +812,18 @@ function onTableReferenceDropEvent(event: Event) {
|
|||
}
|
||||
}
|
||||
|
||||
function registerTableReferenceDropListener() {
|
||||
if (tableReferenceDropListenerRegistered) return;
|
||||
window.addEventListener(DBX_TABLE_REFERENCE_DROP_EVENT, onTableReferenceDropEvent);
|
||||
tableReferenceDropListenerRegistered = true;
|
||||
}
|
||||
|
||||
function unregisterTableReferenceDropListener() {
|
||||
if (!tableReferenceDropListenerRegistered) return;
|
||||
window.removeEventListener(DBX_TABLE_REFERENCE_DROP_EVENT, onTableReferenceDropEvent);
|
||||
tableReferenceDropListenerRegistered = false;
|
||||
}
|
||||
|
||||
let completionEpoch = 0;
|
||||
let completionDebounceTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
|
|
@ -1528,7 +1543,7 @@ onMounted(async () => {
|
|||
view.value = new EditorView({ state, parent: editorRef.value });
|
||||
syncContextMenuState(view.value);
|
||||
syncEditorFontCssVars(liveFontSize.value, ss.fontFamily);
|
||||
window.addEventListener(DBX_TABLE_REFERENCE_DROP_EVENT, onTableReferenceDropEvent);
|
||||
registerTableReferenceDropListener();
|
||||
|
||||
cachedTables = [];
|
||||
scheduleSemanticDiagnostics();
|
||||
|
|
@ -1625,10 +1640,28 @@ watch(
|
|||
{ deep: true },
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
zoomCommitScheduler.dispose();
|
||||
function pauseQueryEditorBackgroundWork() {
|
||||
editorIsActive = false;
|
||||
semanticDiagnosticRunId++;
|
||||
if (semanticDiagnosticTimer) clearTimeout(semanticDiagnosticTimer);
|
||||
window.removeEventListener(DBX_TABLE_REFERENCE_DROP_EVENT, onTableReferenceDropEvent);
|
||||
semanticDiagnosticTimer = null;
|
||||
completionEpoch++;
|
||||
unregisterTableReferenceDropListener();
|
||||
}
|
||||
|
||||
function resumeQueryEditorBackgroundWork() {
|
||||
editorIsActive = true;
|
||||
registerTableReferenceDropListener();
|
||||
scheduleSemanticDiagnostics();
|
||||
}
|
||||
|
||||
onActivated(resumeQueryEditorBackgroundWork);
|
||||
|
||||
onDeactivated(pauseQueryEditorBackgroundWork);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
pauseQueryEditorBackgroundWork();
|
||||
zoomCommitScheduler.dispose();
|
||||
view.value?.destroy();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,17 @@ const globalDdlOpen = ref(false);
|
|||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, useSlots, watch, type Component } from "vue";
|
||||
import {
|
||||
computed,
|
||||
nextTick,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
onActivated,
|
||||
onDeactivated,
|
||||
useSlots,
|
||||
watch,
|
||||
type Component,
|
||||
} from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import {
|
||||
ArrowUp,
|
||||
|
|
@ -2982,6 +2992,7 @@ const canvasRenderStyleKey = computed(
|
|||
);
|
||||
let canvasResizeObserver: ResizeObserver | null = null;
|
||||
let canvasDrawFrame = 0;
|
||||
let dataGridIsActive = true;
|
||||
|
||||
function toggleDataGridRenderMode() {
|
||||
settingsStore.updateEditorSettings({
|
||||
|
|
@ -3000,6 +3011,7 @@ function canvasScrollerElement(): HTMLElement | null {
|
|||
}
|
||||
|
||||
function syncCanvasViewport() {
|
||||
if (!dataGridIsActive) return;
|
||||
const scroller = canvasScrollerElement();
|
||||
if (!scroller) return;
|
||||
canvasViewportWidth.value = scroller.clientWidth;
|
||||
|
|
@ -3013,6 +3025,7 @@ function syncCanvasViewport() {
|
|||
function attachCanvasResizeObserver() {
|
||||
canvasResizeObserver?.disconnect();
|
||||
canvasResizeObserver = null;
|
||||
if (!dataGridIsActive) return;
|
||||
if (!useCanvasGridRows.value) return;
|
||||
const scroller = canvasScrollerElement();
|
||||
if (!scroller) return;
|
||||
|
|
@ -3023,6 +3036,7 @@ function attachCanvasResizeObserver() {
|
|||
}
|
||||
|
||||
function scheduleCanvasDraw() {
|
||||
if (!dataGridIsActive) return;
|
||||
if (!useCanvasGridRows.value || canvasDrawFrame) return;
|
||||
canvasDrawFrame = requestAnimationFrame(() => {
|
||||
canvasDrawFrame = 0;
|
||||
|
|
@ -3345,11 +3359,26 @@ watch(
|
|||
],
|
||||
scheduleCanvasDraw,
|
||||
);
|
||||
onMounted(() => nextTick(attachCanvasResizeObserver));
|
||||
onUnmounted(() => {
|
||||
|
||||
function pauseCanvasGridWork() {
|
||||
dataGridIsActive = false;
|
||||
canvasResizeObserver?.disconnect();
|
||||
if (canvasDrawFrame) cancelAnimationFrame(canvasDrawFrame);
|
||||
});
|
||||
canvasResizeObserver = null;
|
||||
if (canvasDrawFrame) {
|
||||
cancelAnimationFrame(canvasDrawFrame);
|
||||
canvasDrawFrame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function resumeCanvasGridWork() {
|
||||
dataGridIsActive = true;
|
||||
nextTick(attachCanvasResizeObserver);
|
||||
}
|
||||
|
||||
onMounted(resumeCanvasGridWork);
|
||||
onActivated(resumeCanvasGridWork);
|
||||
onDeactivated(pauseCanvasGridWork);
|
||||
onUnmounted(pauseCanvasGridWork);
|
||||
|
||||
function setRowStatusFilter(value: string) {
|
||||
rowStatusFilter.value = value as RowStatusFilter;
|
||||
|
|
@ -4044,10 +4073,7 @@ function getTransposeRecordWidth(recordIndex: number): number {
|
|||
function ensureTransposeRecordWidths(count: number) {
|
||||
if (transposeRecordWidths.value.length !== count) {
|
||||
const prev = transposeRecordWidths.value;
|
||||
const next = new Array(count);
|
||||
for (let i = 0; i < count; i++) {
|
||||
next[i] = i < prev.length ? prev[i] : calcTransposeRecordWidth(i);
|
||||
}
|
||||
const next = Array.from({ length: count }, (_, i) => (i < prev.length ? prev[i] : calcTransposeRecordWidth(i)));
|
||||
transposeRecordWidths.value = next;
|
||||
}
|
||||
}
|
||||
|
|
@ -4749,21 +4775,32 @@ const loadingElapsed = ref(0);
|
|||
let _loadingTimer: ReturnType<typeof setInterval> | undefined;
|
||||
let _loadingStart = 0;
|
||||
|
||||
function stopLoadingElapsedTimer() {
|
||||
clearInterval(_loadingTimer);
|
||||
_loadingTimer = undefined;
|
||||
}
|
||||
|
||||
function startLoadingElapsedTimer() {
|
||||
stopLoadingElapsedTimer();
|
||||
if (!dataGridIsActive || !props.loading) return;
|
||||
_loadingStart = Date.now();
|
||||
loadingElapsed.value = 0;
|
||||
_loadingTimer = setInterval(() => {
|
||||
loadingElapsed.value = Date.now() - _loadingStart;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.loading,
|
||||
(isLoading) => {
|
||||
clearInterval(_loadingTimer);
|
||||
stopLoadingElapsedTimer();
|
||||
console.info(isLoading ? "[DBX][DataGrid:loading:start]" : "[DBX][DataGrid:loading:stop]", {
|
||||
traceId: dataGridTraceId,
|
||||
cacheKey: props.cacheKey,
|
||||
elapsedSinceSetup: dataGridElapsed(),
|
||||
});
|
||||
if (isLoading) {
|
||||
_loadingStart = Date.now();
|
||||
loadingElapsed.value = 0;
|
||||
_loadingTimer = setInterval(() => {
|
||||
loadingElapsed.value = Date.now() - _loadingStart;
|
||||
}, 100);
|
||||
startLoadingElapsedTimer();
|
||||
} else {
|
||||
nextTick(() => {
|
||||
requestAnimationFrame(() => {
|
||||
|
|
@ -4778,6 +4815,9 @@ watch(
|
|||
},
|
||||
);
|
||||
|
||||
onActivated(startLoadingElapsedTimer);
|
||||
onDeactivated(stopLoadingElapsedTimer);
|
||||
|
||||
onUnmounted(() => {
|
||||
cleanupFrames();
|
||||
onSearchSplitResizeEnd();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref, onMounted, onUnmounted, watch } from "vue";
|
||||
import { computed, nextTick, ref, onMounted, onUnmounted, onActivated, onDeactivated, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import {
|
||||
Search,
|
||||
|
|
@ -95,6 +95,8 @@ const createKeyField = ref("");
|
|||
const createKeyScore = ref("0");
|
||||
const createKeyError = ref("");
|
||||
let searchRequestId = 0;
|
||||
let redisBrowserIsActive = true;
|
||||
let redisDbFlushedListenerRegistered = false;
|
||||
|
||||
const valueQuery = computed(() => searchPattern.value.trim());
|
||||
const effectivePattern = computed(() => (searchMode.value === "key" ? searchPattern.value.trim() || "*" : "*"));
|
||||
|
|
@ -216,6 +218,7 @@ async function fillInitialKeyBatch(requestId: number) {
|
|||
}
|
||||
|
||||
async function loadKeys() {
|
||||
if (!redisBrowserIsActive) return;
|
||||
const requestId = ++searchRequestId;
|
||||
loading.value = true;
|
||||
flatKeys.value = [];
|
||||
|
|
@ -574,23 +577,50 @@ function onSearchKeydown(event: KeyboardEvent) {
|
|||
void loadKeys();
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
searchRequestId++;
|
||||
if (searchTimer) clearTimeout(searchTimer);
|
||||
window.removeEventListener("dbx-redis-db-flushed", onRedisDbFlushed);
|
||||
});
|
||||
|
||||
function onRedisDbFlushed(event: Event) {
|
||||
const detail = (event as CustomEvent<{ connectionId: string; db: number }>).detail;
|
||||
if (!detail || detail.connectionId !== props.connectionId || detail.db !== props.db) return;
|
||||
resetLoadedKeys();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
function registerRedisDbFlushedListener() {
|
||||
if (redisDbFlushedListenerRegistered) return;
|
||||
window.addEventListener("dbx-redis-db-flushed", onRedisDbFlushed);
|
||||
redisDbFlushedListenerRegistered = true;
|
||||
}
|
||||
|
||||
function unregisterRedisDbFlushedListener() {
|
||||
if (!redisDbFlushedListenerRegistered) return;
|
||||
window.removeEventListener("dbx-redis-db-flushed", onRedisDbFlushed);
|
||||
redisDbFlushedListenerRegistered = false;
|
||||
}
|
||||
|
||||
function pauseRedisBrowserBackgroundWork() {
|
||||
redisBrowserIsActive = false;
|
||||
searchRequestId++;
|
||||
loading.value = false;
|
||||
loadingMore.value = false;
|
||||
if (searchTimer) clearTimeout(searchTimer);
|
||||
searchTimer = null;
|
||||
unregisterRedisDbFlushedListener();
|
||||
}
|
||||
|
||||
function resumeRedisBrowserBackgroundWork() {
|
||||
redisBrowserIsActive = true;
|
||||
registerRedisDbFlushedListener();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
resumeRedisBrowserBackgroundWork();
|
||||
void loadKeys();
|
||||
});
|
||||
|
||||
onActivated(resumeRedisBrowserBackgroundWork);
|
||||
|
||||
onDeactivated(pauseRedisBrowserBackgroundWork);
|
||||
|
||||
onUnmounted(pauseRedisBrowserBackgroundWork);
|
||||
|
||||
watch(
|
||||
() => props.db,
|
||||
(db) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue