From d5fdb0626e17350138a2e243306d23b0cf8adeb8 Mon Sep 17 00:00:00 2001 From: Ronny Zulaikha <75528127+ronzulu@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:00:36 +1000 Subject: [PATCH] Fixed slow load of flashcard modal (bug introduced in 1.12.0) (#926) * Possibly fixed, for beta testing * Added logging of detailed timing debug * Problem fixed, still needs tidy up * Removed detailed timing logging * Removed detailed timing logging * lint, format and update change log * Removed unused code caught by test coverage checks --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 2 +- docs/changelog.md | 4 ++++ src/NoteQuestionParser.ts | 22 +++++++++++++------- src/SRFile.ts | 17 ++++++++++++++- src/util/TimeTestUtil.ts | 31 ++++++++++++++++++++++++++++ tests/unit/helpers/UnitTestHelper.ts | 7 ------- tests/unit/helpers/UnitTestSRFile.ts | 4 ++++ 8 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 src/util/TimeTestUtil.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bed66b3..1cc39a66 120000 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -docs/changelog.md \ No newline at end of file +docs/changelog.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 651dc17d..9815d5bd 120000 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1 @@ -docs/en/contributing.md \ No newline at end of file +docs/en/contributing.md diff --git a/docs/changelog.md b/docs/changelog.md index 4d80a7d8..4cd65167 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [Unreleased] + +- [BUG] Very slow load of flashcard modal (since 1.11.2) [`#914`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/914) + #### [1.12.2](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.12.1...1.12.2) - fix bug with recognizing frontmatter topic tags (led to missing cards shown for review) [`#920`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/920) diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index f5f197c5..208a03a7 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -30,15 +30,21 @@ export class NoteQuestionParser { onlyKeepQuestionsWithTopicPath: boolean, ): Promise { this.noteFile = noteFile; - const noteText: string = await noteFile.read(); - - // Get the list of tags, and analyse for the topic list - const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); - - const hasTopicPaths = - tagCacheList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item.tag)) || + // For efficiency, we first get the tag list from the Obsidian cache + // (this only gives the tag names, not the line numbers, but this is sufficient for this first step) + const tagCacheList: string[] = noteFile.getAllTagsFromCache(); + const hasTopicPaths: boolean = + tagCacheList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath; + if (hasTopicPaths) { + // Reading the file is relatively an expensive operation, so we only do this when needed + const noteText: string = await noteFile.read(); + + // Now that we know there are relevant flashcard tags in the file, we can get the more detailed info + // that includes the line numbers of each tag + const tagCompleteList: TagCache[] = noteFile.getAllTagsFromText(); + // The following analysis can require fair computation. // There is no point doing it if there aren't any topic paths @@ -51,7 +57,7 @@ export class NoteQuestionParser { // For each question, determine it's TopicPathList [this.frontmatterTopicPathList, this.contentTopicPathInfo] = - this.analyseTagCacheList(tagCacheList); + this.analyseTagCacheList(tagCompleteList); for (const question of this.questionList) { question.topicPathList = this.determineQuestionTopicPathList(question); } diff --git a/src/SRFile.ts b/src/SRFile.ts index bc18b10a..ce283567 100644 --- a/src/SRFile.ts +++ b/src/SRFile.ts @@ -1,9 +1,18 @@ -import { MetadataCache, TFile, Vault, HeadingCache, TagCache, FrontMatterCache } from "obsidian"; +import { + MetadataCache, + TFile, + Vault, + HeadingCache, + getAllTags as ObsidianGetAllTags, + TagCache, + FrontMatterCache, +} from "obsidian"; import { parseObsidianFrontmatterTag } from "./util/utils"; export interface ISRFile { get path(): string; get basename(): string; + getAllTagsFromCache(): string[]; getAllTagsFromText(): TagCache[]; getQuestionContext(cardLine: number): string[]; read(): Promise; @@ -29,6 +38,12 @@ export class SrTFile implements ISRFile { return this.file.basename; } + getAllTagsFromCache(): string[] { + const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; + const result: string[] = ObsidianGetAllTags(fileCachedData) || []; + return result; + } + getAllTagsFromText(): TagCache[] { const result: TagCache[] = [] as TagCache[]; const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; diff --git a/src/util/TimeTestUtil.ts b/src/util/TimeTestUtil.ts new file mode 100644 index 00000000..c4064788 --- /dev/null +++ b/src/util/TimeTestUtil.ts @@ -0,0 +1,31 @@ +import moment from "moment"; + +// These functions were used to diagnose performance issue +// https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/914 + +let testTimeInfo: [string, number][]; + +export function testTimeStart(): void { + testTimeInfo = [["Start", moment().valueOf()]]; +} + +export function testTimeLog(desc: string): void { + if (testTimeInfo == null) testTimeStart(); + testTimeInfo.push([desc, moment().valueOf()]); +} + +export function testTimeGetLapTime(): number { + return moment().valueOf() - testTimeInfo[0][1]; +} + +export function testTimeFormatLapInfo(): string { + let prevTime: number = testTimeInfo[0][1]; + let result: string = ""; + for (let i = 1; i < testTimeInfo.length; i++) { + const thisTime: number = testTimeInfo[i][1]; + result += `\t${testTimeInfo[i][0]}\t${thisTime - prevTime}`; + prevTime = thisTime; + } + result += `\tLapTime\t${testTimeGetLapTime()}|`; + return result; +} diff --git a/tests/unit/helpers/UnitTestHelper.ts b/tests/unit/helpers/UnitTestHelper.ts index e87c8420..2864d16e 100644 --- a/tests/unit/helpers/UnitTestHelper.ts +++ b/tests/unit/helpers/UnitTestHelper.ts @@ -55,10 +55,3 @@ export function unitTest_GetAllTagsFromTextEx(text: string): TagCache[] { } return result; } - -export function unitTest_GetAllTagsFromText(text: string): string[] { - const tagRegex = /#[^\s#]+/gi; - const result: RegExpMatchArray = text.match(tagRegex); - if (!result) return []; - return result; -} diff --git a/tests/unit/helpers/UnitTestSRFile.ts b/tests/unit/helpers/UnitTestSRFile.ts index 3110f892..4878ca82 100644 --- a/tests/unit/helpers/UnitTestSRFile.ts +++ b/tests/unit/helpers/UnitTestSRFile.ts @@ -19,6 +19,10 @@ export class UnitTestSRFile implements ISRFile { return ""; } + getAllTagsFromCache(): string[] { + return unitTest_GetAllTagsFromTextEx(this.content).map((item) => item.tag); + } + getAllTagsFromText(): TagCache[] { return unitTest_GetAllTagsFromTextEx(this.content); }