React Native(or JS) Evil - setInterval

MJ Studio
MJ Studio
Published in
5 min readMay 14, 2021

--

setInterval is nothing better than setTimeout and will crack your application eventually. But the evil is JS itself 🤔

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
1001
console.log
2002
console.log
3007
console.log
4008
console.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! 😀

--

--