You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `nextCard()` function in `SessionController.ts` is experiencing performance issues, with execution times ranging from acceptable to several seconds. The root cause of this inconsistency appears to be in the data retrieval logic, specifically within the `ELONavigator` class, which is responsible for fetching new and review cards for a study session.
4
+
5
+
## The Problem: N+1 Queries
6
+
7
+
The primary performance bottleneck is a classic "N+1 query" problem in the `ELONavigator.getPendingReviews()` method. This method makes two separate, sequential database calls:
8
+
9
+
1.**`this.user.getPendingReviews(this.course.getCourseID())`**: Fetches a list of all pending review cards for the user.
10
+
2.**`this.course.getCardEloData(reviews.map((r) => r.cardId))`**: For each card returned in the first query, this method makes an additional query to retrieve the card's ELO data.
11
+
12
+
This means that if a user has 20 pending reviews, the `getPendingReviews()` method will make 21 database queries (1 to get the reviews, and 20 to get the ELO data for each review). This is highly inefficient and is the most likely cause of the long and unpredictable delays.
13
+
14
+
A similar, though likely less severe, issue exists in the `getNewCards()` method, which also makes multiple database calls.
15
+
16
+
## The Solution: Server-Side Data Aggregation
17
+
18
+
The most effective way to resolve this issue is to move the data aggregation logic to the server-side (i.e., into a CouchDB view or a server-side function). Instead of making multiple round trips to the database, we can create a single query that joins the review and ELO data and returns it in a single response.
19
+
20
+
This will require the following changes:
21
+
22
+
1.**Create a new CouchDB view:** This view will be responsible for joining the user's pending reviews with the corresponding card ELO data.
23
+
2.**Modify `ELONavigator.getPendingReviews()`:** This method will be updated to query the new CouchDB view instead of making two separate database calls.
24
+
3.**(Optional but Recommended)****Refactor `ELONavigator.getNewCards()`:** This method should also be refactored to reduce the number of database calls.
25
+
26
+
## Recommendation
27
+
28
+
I recommend that we proceed with the server-side data aggregation approach. This will significantly improve the performance and reliability of the `nextCard()` function and provide a better user experience.
29
+
30
+
I will now create a plan to implement these changes.
This document amends the initial assessment in `a.1.assessment.md`.
4
+
5
+
## Refined Problem Analysis
6
+
7
+
My initial analysis correctly identified that multiple database round-trips were the source of the performance issue. However, I incorrectly pinpointed *when* these trips occurred.
8
+
9
+
The user correctly pointed out that the latency does not happen during the initial `prepareSession()` call, but rather *after* each `nextCard()` call. Here's the corrected flow:
10
+
11
+
1.`prepareSession()` populates the internal queues (`reviewQ`, `newQ`) with `StudySessionItem` objects. These objects are lightweight and only contain IDs and metadata, not the full card content. This initial population is relatively fast.
12
+
2. The UI calls `nextCard()`, which dequeues a single `StudySessionItem`. This is a fast, in-memory operation.
13
+
3. The UI receives the `StudySessionItem` and now has a `cardID`. To render the card, the UI must then make **two separate, sequential network requests** to CouchDB:
14
+
1. Fetch the main card document.
15
+
2. Fetch the card's associated data document, which is pointed to by the main card document.
16
+
4. These two on-demand fetches for every single card are the direct cause of the interactive lag the user experiences.
17
+
18
+
## Revised Recommendation
19
+
20
+
The user's proposal to maintain a client-side buffer of fully "hydrated" cards is the correct approach. This strategy involves pre-fetching the next few cards in the background so they are immediately available in memory when `nextCard()` is called. This moves the latency from an interactive "blocking" operation to a non-blocking background task.
21
+
22
+
I agree with this approach and will create a new plan based on it.
This plan outlines the steps to implement a client-side pre-fetching strategy to eliminate interactive lag when displaying study cards.
4
+
5
+
## Core Strategy
6
+
7
+
We will modify the `SessionController` to maintain a small, rolling buffer of fully hydrated card objects. Instead of the UI being responsible for fetching card data on-demand, the `SessionController` will proactively fetch the next few cards in the background.
8
+
9
+
## Implementation Steps
10
+
11
+
1.**Introduce a Hydrated Card Queue:**
12
+
* Create a new queue within `SessionController`, let's call it `hydratedQ`. This queue will store fully resolved card objects, including their view and data components.
13
+
* The `nextCard()` function will now draw directly from this `hydratedQ`.
14
+
15
+
2.**Implement a Pre-fetching Mechanism:**
16
+
* Create a new private method in `SessionController`, e.g., `_fillHydratedQueue()`.
17
+
* This method will run in the background and ensure that `hydratedQ` always contains a target number of cards (e.g., 5).
18
+
* It will peek at the upcoming card IDs in the `reviewQ` and `newQ`, fetch their full data from CouchDB, and push the hydrated objects into `hydratedQ`.
19
+
20
+
3.**Modify `nextCard()` Logic:**
21
+
* The `nextCard()` function will be updated to:
22
+
1. Dequeue a hydrated card from `hydratedQ` and return it to the UI.
23
+
2. After dequeuing, it will trigger the `_fillHydratedQueue()` method asynchronously to ensure the buffer is refilled in the background.
24
+
25
+
4.**Initial Hydration:**
26
+
* During `prepareSession()`, after the initial queues are populated, we will make an initial call to `_fillHydratedQueue()` to populate the buffer for the start of the session.
27
+
28
+
## Task Breakdown
29
+
30
+
I will create a `a.4.todo.md` file with a detailed task breakdown for implementing this plan.
-[x]**Task 1.1:** In `SessionController.ts`, define a new interface `HydratedCard` that represents a fully resolved card object (including its view and data).
8
+
-[x]**Task 1.2:** In `SessionController.ts`, add a new private queue property: `private hydratedQ: ItemQueue<HydratedCard> = new ItemQueue<HydratedCard>();`
9
+
-[x]**Task 1.3:** In `SessionController.ts`, create a new private async method `_fillHydratedQueue()`. This method will be responsible for the pre-fetching logic.
10
+
11
+
## Phase 2: Pre-fetching Logic
12
+
13
+
-[ ]**Task 2.1:** Inside `_fillHydratedQueue()`, implement the logic to determine how many cards to fetch (target buffer size is 5).
14
+
-[ ]**Task 2.2:** Inside `_fillHydratedQueue()`, peek at the next items in `reviewQ` and `newQ` to get their card IDs.
15
+
-[ ]**Task 2.3:** For each card ID, implement the necessary calls to fetch the full card document and its associated data document from CouchDB.
16
+
-[ ]**Task 2.4:** Once fetched, create `HydratedCard` objects and enqueue them into `hydratedQ`.
17
+
18
+
## Phase 3: Update `nextCard()` and `prepareSession()`
19
+
20
+
-[ ]**Task 3.1:** Modify the `nextCard()` function to dequeue from `hydratedQ` instead of the other queues.
21
+
-[ ]**Task 3.2:** After dequeuing in `nextCard()`, add a non-blocking call to `_fillHydratedQueue()` to trigger the background pre-fetch.
22
+
-[ ]**Task 3.3:** In `prepareSession()`, after the `reviewQ` and `newQ` are populated, add an initial `await this._fillHydratedQueue()` call to ensure the buffer is ready for the first card.
23
+
24
+
## Phase 4: UI and Verification
25
+
26
+
-[ ]**Task 4.1:** Adjust the UI component that calls `nextCard()` to expect the new `HydratedCard` object, removing its own data-fetching logic.
27
+
-[ ]**Task 4.2:** Manually test the study session flow to confirm that cards load quickly and that there are no errors.
28
+
-[ ]**Task 4.3:** Use browser developer tools to verify that network requests for card data are happening *before* a card is displayed, not when it is requested.
0 commit comments