Ivan Akulov
@iamakulov.com
Web perf engineer @ Framer. Prev. web perf consultant (Google, Appsmith, Toggl, etc). Getting React interactions 2-4x faster. GDE. He/him 🏳️🌈
Okay, so this is pretty wild: apparently, in Chromium, the deeper you are in the call stack, the slower your `setTimeout()` calls become?
gist.github.com/iamakulov/85...
gist.github.com/iamakulov/85...
November 10, 2025 at 4:58 PM
Okay, so this is pretty wild: apparently, in Chromium, the deeper you are in the call stack, the slower your `setTimeout()` calls become?
gist.github.com/iamakulov/85...
gist.github.com/iamakulov/85...
Why are native setTimeout and clearTimeout calls so expensive? Like, here it takes 1.5 ms. What’s the technical reason it’s so slow?
Just 100-200 of those in a row (trivial if you’re mounting a bunch of React components that set timers) will easily block the page.
Just 100-200 of those in a row (trivial if you’re mounting a bunch of React components that set timers) will easily block the page.
November 9, 2025 at 10:19 PM
Why are native setTimeout and clearTimeout calls so expensive? Like, here it takes 1.5 ms. What’s the technical reason it’s so slow?
Just 100-200 of those in a row (trivial if you’re mounting a bunch of React components that set timers) will easily block the page.
Just 100-200 of those in a row (trivial if you’re mounting a bunch of React components that set timers) will easily block the page.
Belated hi from @perfnow.nl! Come talk to us (me & @kurtextrem.de) about React performance, Framer sites, LCP/INP and more :D
October 31, 2025 at 10:05 AM
Belated hi from @perfnow.nl! Come talk to us (me & @kurtextrem.de) about React performance, Framer sites, LCP/INP and more :D
Neat lil learning from today’s @perfnow.nl (via Umar Hansa):
You can now throttle individual requests in Chrome!
Neat for experimenting with stuff like
- lazy-loading: does the UI look okay if this chunk takes MUCH longer to arrive
- resilience: what happens if this specific CDN is extremely slow
You can now throttle individual requests in Chrome!
Neat for experimenting with stuff like
- lazy-loading: does the UI look okay if this chunk takes MUCH longer to arrive
- resilience: what happens if this specific CDN is extremely slow
October 30, 2025 at 5:29 PM
Neat lil learning from today’s @perfnow.nl (via Umar Hansa):
You can now throttle individual requests in Chrome!
Neat for experimenting with stuff like
- lazy-loading: does the UI look okay if this chunk takes MUCH longer to arrive
- resilience: what happens if this specific CDN is extremely slow
You can now throttle individual requests in Chrome!
Neat for experimenting with stuff like
- lazy-loading: does the UI look okay if this chunk takes MUCH longer to arrive
- resilience: what happens if this specific CDN is extremely slow
This lil boy (www.framer.com/updates/cms...) actually took multiple weeks of full-time work! That’s because we didn’t only fix copy-paste papercuts, we also took an opportunity to improve Framer’s text editing architecture.
Story time!
Story time!
October 24, 2025 at 10:18 AM
This lil boy (www.framer.com/updates/cms...) actually took multiple weeks of full-time work! That’s because we didn’t only fix copy-paste papercuts, we also took an opportunity to improve Framer’s text editing architecture.
Story time!
Story time!
til oxlint does some insane tricks (custom js ast interface that understands rust memory layout!) to make js plugins fast github.com/oxc-project...
October 21, 2025 at 9:58 AM
til oxlint does some insane tricks (custom js ast interface that understands rust memory layout!) to make js plugins fast github.com/oxc-project...
something very cool to see: Chrome recently shipped automatic <link rel="prefetch"> for all links in viewport
you could do it previously with libs like Quicklink, but it’s super cool to see this implemented natively
(it’s off by default, enabled with one html tag)
you could do it previously with libs like Quicklink, but it’s super cool to see this implemented natively
(it’s off by default, enabled with one html tag)
October 20, 2025 at 10:00 AM
something very cool to see: Chrome recently shipped automatic <link rel="prefetch"> for all links in viewport
you could do it previously with libs like Quicklink, but it’s super cool to see this implemented natively
(it’s off by default, enabled with one html tag)
you could do it previously with libs like Quicklink, but it’s super cool to see this implemented natively
(it’s off by default, enabled with one html tag)
feels so good to be writing something again huh
October 8, 2025 at 12:20 AM
feels so good to be writing something again huh
Got bitten by `new URL()` today. Guess why this doesn’t work?
October 1, 2025 at 9:59 AM
Got bitten by `new URL()` today. Guess why this doesn’t work?
soon in @Framer.com: much better ⌘C ⌘V with google docs, notion, craft, and every other editor out there
(my lil non-performance side project)
(my lil non-performance side project)
September 30, 2025 at 2:59 PM
soon in @Framer.com: much better ⌘C ⌘V with google docs, notion, craft, and every other editor out there
(my lil non-performance side project)
(my lil non-performance side project)
⚡ Lighthouse (incorrectly) punishes preloading
If you’re like me, you probably struggled with Lighthouse scores at least once. “I already optimized everything; why is my score still yellow?”
Often, the cause is there’s more to optimize. But sometimes, it’s Lighthouse itself.
If you’re like me, you probably struggled with Lighthouse scores at least once. “I already optimized everything; why is my score still yellow?”
Often, the cause is there’s more to optimize. But sometimes, it’s Lighthouse itself.
June 12, 2025 at 10:46 AM
⚡ Lighthouse (incorrectly) punishes preloading
If you’re like me, you probably struggled with Lighthouse scores at least once. “I already optimized everything; why is my score still yellow?”
Often, the cause is there’s more to optimize. But sometimes, it’s Lighthouse itself.
If you’re like me, you probably struggled with Lighthouse scores at least once. “I already optimized everything; why is my score still yellow?”
Often, the cause is there’s more to optimize. But sometimes, it’s Lighthouse itself.
Reposted by Ivan Akulov
May 29, 2025 at 8:58 AM
📝 Wrote about that one time I was doing performance work and ran into an eval()-based JS minifier from 2004.
(Also, it’s compatible with ES2024, guess what)
3perf.com/blog/packer/
(Also, it’s compatible with ES2024, guess what)
3perf.com/blog/packer/
March 24, 2025 at 11:00 AM
📝 Wrote about that one time I was doing performance work and ran into an eval()-based JS minifier from 2004.
(Also, it’s compatible with ES2024, guess what)
3perf.com/blog/packer/
(Also, it’s compatible with ES2024, guess what)
3perf.com/blog/packer/
Introducing @Framer.com Code Boundaries. No more optimization errors, no more blank pages, and no more searching for broken Components.
(Or: how we went down the rabbit hole of React error handling for a month 🧵)
(Or: how we went down the rabbit hole of React error handling for a month 🧵)
March 17, 2025 at 4:41 PM
Introducing @Framer.com Code Boundaries. No more optimization errors, no more blank pages, and no more searching for broken Components.
(Or: how we went down the rabbit hole of React error handling for a month 🧵)
(Or: how we went down the rabbit hole of React error handling for a month 🧵)
Stumbled upon a fun Chrome issue where you can get a high CLS score when nothing jumps on the screen – simply by using `content-visibility: auto`!
Filed a bug: issues.chromium.org/issues/3911...
Filed a bug: issues.chromium.org/issues/3911...
January 20, 2025 at 11:12 PM
Stumbled upon a fun Chrome issue where you can get a high CLS score when nothing jumps on the screen – simply by using `content-visibility: auto`!
Filed a bug: issues.chromium.org/issues/3911...
Filed a bug: issues.chromium.org/issues/3911...
Reposted by Ivan Akulov
So excited to have @iamakulov.com this year on the conference. Stay tuned for the full lineup announcement!
👨💻 Speaker Spotlight #JSHeroes 2025:
Ivan Akulov works as a Senior Performance Engineer at Framer and will dive deep into the internals of React to showcase where performance is lost and gained in a modern frontend application.
Ivan Akulov works as a Senior Performance Engineer at Framer and will dive deep into the internals of React to showcase where performance is lost and gained in a modern frontend application.
January 16, 2025 at 4:41 PM
So excited to have @iamakulov.com this year on the conference. Stay tuned for the full lineup announcement!
This is the most comprehensive deep overview of React INP optimizations I’ve seen to date:
Did you know that jQuery outperforms React, what? 😳
Sounds like clickbait, but is reality. The HTTP Archive shows 82% of sites that use jQuery have good INP on mobile📱, while only 67% do when they use React⚛️.
Not just sites, also libraries. Let's fix that👇#webperf
kurtextrem.de/posts/improv...
Sounds like clickbait, but is reality. The HTTP Archive shows 82% of sites that use jQuery have good INP on mobile📱, while only 67% do when they use React⚛️.
Not just sites, also libraries. Let's fix that👇#webperf
kurtextrem.de/posts/improv...
How To Improve INP: React⚛️
All-in-one guide for improving Interaction-to-Next-Paint (INP) Core Web Vital in React applications. Introduces the useAfterPaintEffect hook.
kurtextrem.de
December 3, 2024 at 12:57 PM
This is the most comprehensive deep overview of React INP optimizations I’ve seen to date:
One of the best productivity tips I have ever learned at Framer (from @eelco.lempsink.nl) is:
Whenever you want to ask a teammate for help, don’t DM them. Instead, always post your question in a channel (and cc them).
Whenever you want to ask a teammate for help, don’t DM them. Instead, always post your question in a channel (and cc them).
December 3, 2024 at 12:36 PM
One of the best productivity tips I have ever learned at Framer (from @eelco.lempsink.nl) is:
Whenever you want to ask a teammate for help, don’t DM them. Instead, always post your question in a channel (and cc them).
Whenever you want to ask a teammate for help, don’t DM them. Instead, always post your question in a channel (and cc them).
I found the dumbest way to preload an iframe ahead of time:
<iframe src="..." sandbox="allow-same-origin">
• Downloads the iframe + its CSS/JS/etc
• Puts these resources into the cache, so they’re there when you need them later
• Critically, doesn’t execute any JS at all
<iframe src="..." sandbox="allow-same-origin">
• Downloads the iframe + its CSS/JS/etc
• Puts these resources into the cache, so they’re there when you need them later
• Critically, doesn’t execute any JS at all
December 2, 2024 at 3:43 PM
I found the dumbest way to preload an iframe ahead of time:
<iframe src="..." sandbox="allow-same-origin">
• Downloads the iframe + its CSS/JS/etc
• Puts these resources into the cache, so they’re there when you need them later
• Critically, doesn’t execute any JS at all
<iframe src="..." sandbox="allow-same-origin">
• Downloads the iframe + its CSS/JS/etc
• Puts these resources into the cache, so they’re there when you need them later
• Critically, doesn’t execute any JS at all
Today in React wishlist: support for setting several refs on a single
November 18, 2024 at 9:18 PM
Today in React wishlist: support for setting several refs on a single
Reposted by Ivan Akulov
This fix for this is so slick: instead of reverting back to the old behavior where Suspense fallbacks have to wait for suspended siblings to render, the new feature commits fallbacks immediately, then schedules a render for the siblings after to "pre-warm" the lazy requests in the tree.
react@19.0.0-rc1 is out today with a replacement for sibling pre-rendering. Give it a try and maybe we can ship React 19 soon?
github.com/facebook/rea...
github.com/facebook/rea...
[React 19] Disabling prerendering siblings of suspended components breaking common pattern · Issue #29898 · facebook/react
Summary I'm creating this issue to continue the discussion that spawned in the already merged PR (#26380) Several community members have raised concerns about this change and it has gained traction...
github.com
November 14, 2024 at 10:07 PM
This fix for this is so slick: instead of reverting back to the old behavior where Suspense fallbacks have to wait for suspended siblings to render, the new feature commits fallbacks immediately, then schedules a render for the siblings after to "pre-warm" the lazy requests in the tree.
Reposted by Ivan Akulov
you know what actually fuck you and in fact fuck the horse you rode in on
"one of us only tells the truth and one only lies"-ass CSS property
"one of us only tells the truth and one only lies"-ass CSS property
November 14, 2024 at 8:31 PM
you know what actually fuck you and in fact fuck the horse you rode in on
"one of us only tells the truth and one only lies"-ass CSS property
"one of us only tells the truth and one only lies"-ass CSS property
English
300
Connect Bluesky
Enter your Bluesky handle and app password to unlock posting, likes, and your Following feed.
Need an app password? Open Bluesky, go to Settings > App passwords, and create a new one.
Connect with Bluesky
Sign in with your Bluesky account to unlock posting, likes, and your Following feed.