Did you ever develop a time related feature in your react native application like timer or do something intervally? As the name suggest, the best option for that seems to using setInterval
in Javascript.
But you are wrong šµ. there are couple of reason and have to know thoroughly why it is.
1. Javascript is a single thread language
Yes, it is a famous fact. The asynchronization API in JS is not actually in JS itself. Depend on your devlopment platform, the implementation of these APIs are provided by platform(NodeJS, Web brower, etcā¦).
If you are not familiar with what i am saying, then check this video and understand how JS makes async task possible.
With this reason, the JS utilize Callback Queue for response from async APIs in platform environment you have.
Imagine that the speed increase task in Callback Queue is faster than task processing speed in queue. Is there any automatical strategy for handling bottlenect in Callback Queue in Javascript internally? No Never.
Even if asynchronous waiting for time is job for WebAPI, the execution of task is live in JS Thread(Yes it is single). Imagine that dummy code.
setInterval(() => {
taskConsumes200Ms(); // JS thread is stuck 200ms
}, 100);
The task(callback) is pushed to queue every 100ms(not exactly, but same interval speed). But your JS thread is stuck 200ms for processing every task. Yes JS thread debtes almost 100ms in every task. This will make your app stuck eventually.
2. React Native JS code is executed holy slow
You can say that āMy callback will be executed within interval 100%. So, there is no threat from queue stuckā. Well.. everybody can expect the result but nobody can assure that.
The exact execution time depends clients device computing power and so many variables affect that. Yes, It worked fine on my machine problem.
The old device is stucked in callback queue hell and the newer one is fine.
In the mobile device, even though the newer devices have very fast CPU, but the computing resources are limited than desktop or others. Also, the React Native platform is not 100% pure JS application. JS engine is just added to native Android, iOS application. Also, there is a bridge for communication between JS thread <-> Native thread. It makes app more slow. And the execution of React Native application is not optimized because it is just highly abstracted framework to develop two platform simultansouly in many area. Especially Android suffers sucking slow problem. The JS engine made by Facebook called Hermes didnāt improve this problem well. And I experienced it!
3. You canāt make 100% wihhout error timer in JS simply and there is no reason for making that too
In JS hosting environment(NodeJS, Web browser), timer(setTimeout
, setInterval
) is handled by Macro queue and Promise
is handled by Micro queue.
Can you assume the result of the following snippet?
const startTime = new Date().getTime();
setInterval(() => {
const diffMs = new Date().getTime() - startTime;
console.log(diffMs); // 1000, 2000, 3000 ???
}, 1000);
The result isā¦
console.log
1001console.log
2002console.log
3007console.log
4008console.log
5010
Yes the result is saying: āFuck you I wonāt behave what you wantā.
If you want to make countdown timer every 1 sec, then set interval delay under 1 sec. It is ridiculous. But the lower interval delay, the bigger possibility stuck application.
Nobody can implement 100% no error exact timer in JS with setInterval or setTimeout.
Instead, just use recursive setTimeout
for that, it is stuck-safe because next callback is scheduled when JS thread is idle not from Web API.
const timer = () => {
setTimeout(() => {
// do your work
timer();
}, 1000);
};
timer();
setInterval
and setTimeout
are all inaccurate. Then we should take safety instead. Sometimes, the timer sec will decrease 2 sec not 1 sec. But is it really serious problem? No. We should prevent ANR(Application Not responding) more seriously.
This is my implementation for setInterval
with setTimeout
. It is not 100% well implemented and you can override it!
export class TimeoutHandler {
private handlerRef: { id: any } = { id: -1 };
get handler(): any {
return this.handlerRef.id;
}
set handler(n: any) {
this.handlerRef.id = n;
}
clear() {
clearTimeout(this.handlerRef.id as any);
}
}
export default function setIntervalWithTimeout(
callback: (clear: () => void) => any,
intervalMs: number,
handleWrapper = new TimeoutHandler(),
): TimeoutHandler {
let cleared = false;
const timeout = () => {
handleWrapper.handler = setTimeout(() => {
callback(() => {
cleared = true;
handleWrapper.clear();
});
if (!cleared) {
timeout();
}
}, intervalMs);
};
timeout();
return handleWrapper;
}
Conclusion
I recently removed all setInterval
in my React Native application and the application has been faster noticeably.
Personally, I donāt like Javascriptā¦ It is so legacy and there are many not unioned variations and transpiling, linting process(ESLint, Babel, Prettier, ā¦).
But if we have to make application with JS, then understand it 100% is needed. I donāt think JS is a easy language for programming begginers.
Anyway, I wish you can enhance your application with replacing setInterval
with other API.
Thank you for reading! š
- Github
- Website
- Medium Blog, Dev Blog, Naver Blog
- Contact: mym0404@gmail.com