Skip to content

Faster thumbs#172

Merged
CrystalSplitter merged 7 commits into
masterfrom
faster-thumbs
Jun 15, 2026
Merged

Faster thumbs#172
CrystalSplitter merged 7 commits into
masterfrom
faster-thumbs

Conversation

@CrystalSplitter

Copy link
Copy Markdown
Collaborator

Implement lazy-loading for thumbnail fetching.

We give thumbnails exactly 1 second to load to prevent flashing, but after that we give up and let them load
in the background without waiting. This is implemented by keeping track of an item's thumbnailJobs, and
then dispatching state/updating the DB on their completion.

Fixes #171.

Before, we it was possible to update the item without actually dispatching to
the Redux state. This fixes this, in a very convoluted way.
It still could be better, but it's a lot better than before.

Now we have some rate-limitting on thumbnail extraction, so hopefully we won't get 429s.
@CrystalSplitter

CrystalSplitter commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

Hmm. This has a bug where thumbnails will show up as black boxes occasionally, even when we already have the thumbnails fetched and stored in the DB.

Not sure why. Perhaps something to do with the thumbnail canvas caching?

@CrystalSplitter

Copy link
Copy Markdown
Collaborator Author

Hmm. This has a bug where thumbnails will show up as black boxes occasionally, even when we already have the thumbnails fetched and stored in the DB.

Not sure why. Perhaps something to do with the thumbnail canvas caching?

Oh; that may have been because of network throttling I had during testing. That would make more sense.

Much more ergonomic to use a method fetch rather than pass it
as the final argument of a long method.
This is more clean up work, should not have any functional change.
This adds a number of stricter static checks, as well
as fixes for thumbnail parsing with redux ordering.
@nubesurrealista

Copy link
Copy Markdown
Collaborator

If you need some testing I'm here haha

@CrystalSplitter

Copy link
Copy Markdown
Collaborator Author

Always happy to have more testers! I found a few bugs from playing around with it, but so far it's been clean (and much faster).

@CrystalSplitter

Copy link
Copy Markdown
Collaborator Author

Testing this more, this feed: https://www.nicchan.me/feed.xml from Nic chan crashes Fluentflame Reader when this feature is merged.

Stack trace:

cached-img.tsx:22  HEAD https://res.cloudinary.com/nicchan/image/upload/w_1200,h_630,c_limit,f_auto/v1726638875/ net::ERR_ABORTED 400 (Bad Request)
loadContentType @ cached-img.tsx:22
renderImage @ cached-img.tsx:126
render @ cached-img.tsx:225
Ba @ react-dom.production.min.js:182
Fa @ react-dom.production.min.js:181
vs @ react-dom.production.min.js:263
ul @ react-dom.production.min.js:246
ll @ react-dom.production.min.js:246
tl @ react-dom.production.min.js:239
(anonymous) @ react-dom.production.min.js:123
t.unstable_runWithPriority @ scheduler.production.min.js:19
Wo @ react-dom.production.min.js:122
Ko @ react-dom.production.min.js:123
qo @ react-dom.production.min.js:122
nl @ react-dom.production.min.js:240
notify @ Subscription.js:15
notifyNestedSubs @ Subscription.js:85
o @ Subscription.js:90
h @ redux.js:296
(anonymous) @ index.js:20
dispatch @ redux.js:691
(anonymous) @ feed.ts:178
Promise.then
(anonymous) @ feed.ts:177
(anonymous) @ index.js:16
onClick @ menu.tsx:44
n._onNavButtonLinkClicked @ Nav.base.js:229
r._onClick @ BaseButton.js:197
s @ react-dom.production.min.js:14
h @ react-dom.production.min.js:14
(anonymous) @ react-dom.production.min.js:14
y @ react-dom.production.min.js:15
ot @ react-dom.production.min.js:52
nt @ react-dom.production.min.js:51
it @ react-dom.production.min.js:52
dt @ react-dom.production.min.js:56
F @ react-dom.production.min.js:287
j @ react-dom.production.min.js:19
Yt @ react-dom.production.min.js:70
$t @ react-dom.production.min.js:69
t.unstable_runWithPriority @ scheduler.production.min.js:19
Wo @ react-dom.production.min.js:122
O @ react-dom.production.min.js:287
Kt @ react-dom.production.min.js:68
res.cloudinary.com/nicchan/image/upload/w_1200,h_630,c_limit,f_auto/v1726638875/:1  GET https://res.cloudinary.com/nicchan/image/upload/w_1200,h_630,c_limit,f_auto/v1726638875/ 400 (Bad Request)

@CrystalSplitter

CrystalSplitter commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

Ah, this is because that image hosting subdomain https://res.cloudinary.com/nicchan is dead. We should gracefully fail when we can no longer fetch thumbnails.

@CrystalSplitter

Copy link
Copy Markdown
Collaborator Author

The freezing present in #172 (comment) is not because of this PR, but rather a bug in the image cache where we can enter an infinite loop where the image fails to decode. Specifically, calling forceUpdate causes non-terminating recursion here:

This is worth fixing in this PR too, I think.

Previously, we had a bug where failing to decode an image
would lead to an infinite loop as we kept trying to decode
it over and over again. We don't actually need this, so
keep track of failures.
@CrystalSplitter

Copy link
Copy Markdown
Collaborator Author

I believe this is fully functional. If you do notice issues, please do let me know though! Things I'm specifically looking out for:

  • Black thumbnails
  • Weird rendering issues with thumbnail canvases
  • Missing thumbnails
  • Flickering thumbnails
  • Layout shifts

If you see any of those, they could be related to this feature.

@CrystalSplitter CrystalSplitter merged commit 751c991 into master Jun 15, 2026
5 checks passed
@CrystalSplitter CrystalSplitter deleted the faster-thumbs branch June 15, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fetching Thumbnails Blocks for Too Long

2 participants