I will share with you a story of performance improvement at my site.
Prerequisite
I must tell you about prerequisite like npm dependencies before introducing the case.
The website that I improved is Instagram Hashtag Translator .
It helps us to translate Instagram hashtags.
The technical conditions are as follows.
- npm dependencies
- React v18.2.0
- Next.js v13.0.5
- Hosting
- Vercel
I measured the time it took to process the JavaScript when clicking the translate button.
const clickHandler = () => {
const start = performance.now();
// ...
// ...processing
// ...
console.log(Math.ceil((performance.now() - start) * 100) / 100);
}
Before Improvement
const clickHandler = async () => {
// Dynamic import
const { default: sendGaEvent } = await import(
'~/lib/analytics/sendGaEvent'
);
// ...
// Send analytics data
sendGaEvent(data);
// ...
// Dynamic import
const { default: translate } = await import('~/infra/translate');
// ...
}
There are notable 2 points.
- Import modules when user clicked the button
- Send analytics data
1. Import modules when user clicked the button
By using dynamic import , we can reduces the code needed on the initial load of our application.
It likes good idea, but there also is problem.
Dynamic import gives users bad responsiveness because it is not until they clicked the button that browsers load modules.
2. Send analytics data
Is it important to send analytics data?
This answer is no.
We want to have JavaScript main thread process important tasks
like translating words as much as possible.
After Improvement
I improve the performance by using idle-task
.
https://github.com/hiroki0525/idle-task
import { setIdleTask, forceRunIdleTask } from 'idle-task';
// point 1
const importSendGaEventTaskId = setIdleTask(
() => import('~/common/analytics/sendGaEvent')
);
const importTranslateTaskId = setIdleTask(() => import('~/infra/translate'));
const clickHandler = async () => {
// point 1
const { default: sendGaEvent } = await forceRunIdleTask(
importSendGaEventTaskId
);
// ...
// point 2
setIdleTask(() => sendGaEvent(data));
// ...
// point 1
const { default: translate } = await forceRunIdleTask(importTranslateTaskId);
// ...
}
point 1
I prepare browsers to load modules during their idle periods 。
const importSendGaEventTaskId = setIdleTask(
() => import('~/common/analytics/sendGaEvent')
);
const importTranslateTaskId = setIdleTask(() => import('~/infra/translate'));
setIdleTask
can register tasks which will be executed when browsers are idle.
const { default: sendGaEvent } = await forceRunIdleTask(
importSendGaEventTaskId
);
const { default: translate } = await forceRunIdleTask(importTranslateTaskId);
// ...
}
We can get the results by using forceRunIdleTask
.
It will not always be idle if browsers are busy.
forceRunIdleTask
gives us the result from cache when the task had been executed, otherwise idle-task
run immediately.
point 2
Send analytics data during a browser's idle periods 。
setIdleTask(() => sendGaEvent(data));
As I have already told you, setIdleTask
help us to execute tasks when browsers are idle.
It seems to have solved all my problems!
Result
Before(ms) | After(ms) | |
---|---|---|
1st | 1110.8 | 1048.8 |
2nd | 1191.2 | 1068.9 |
3rd | 1070.4 | 1028.4 |
4th | 1084.8 | 1023.2 |
5th | 1099.4 | 1080.8 |
average | 1111.3 | 1050.0 |
That's an improvement of about 5.5% 🎉.
In fact, the main translation process itself takes about 1,000 ms , so if we consider the non-main process, the improvement is about 55%.
In absolute terms, this is an improvement of 50 to 60 ms, which may not seem like much numerically at first glance, but an improvement of 50 to 60 ms is significant.
In light of the RAIL model, users will feel comfortable when the execution time is roughly 100 ms or less (50 ms is recommended as a guideline).
Considering this, an improvement of 50 to 60 ms would be significant .
Conclusion
I improved the performance of Instagram Hashtag Translator by using idle-task
.
https://github.com/hiroki0525/idle-task
If you found this helpful, please help someone else by sharing it or tagging someone in the comments!
Thanks!
Top comments (0)