Prevent Endless Loops in JavaScript ꔛ
Ingo Steinke, web developer
Posted on May 23, 2022
I accidentally created an endless loop in JavaScript that made my browser crash. How is this even possible in 2022?
Consider the following code:
const mightBeZero = 0;
const maxIterations = 100 / mightBeZero;
console.log(`maxIterations: ${maxIterations}`);
for (let i = 0; i < maxIterations; i++) {
// do costly stuff like appending cloned DOM nodes
}
While at least CodePen seems smart enough to protect their users, ESLint seems to have nothing to criticize except that I used ++
instead of += 1
.
Despite the endless loop, why does division by zero equals Infinity
in JavaScript while many other programming languages throw a DivisionByZero
exception?
And why did we fail to handle JavaScript's division by zero properly in our code?
Failure Chain
- My quick and dirty, naive, happy-path code failed to envision edge cases (using
offsetWidth
without checking for 0 width of a hiddenwidth: auto
element) - JavaScript failed to throw a Division by Zero exception but calculating
x / 0 = Infinity
instead - JavaScript not refusing to do a loop `for (let i=0; i < Infinity; i += 1)
- eslint failed to warn (after "fixing"
i++
toi += 1
everything seemed to be fine?!) - PhpStorm code inspection, quite smart even for JavaScript otherwise, did not warn either.
- A coworker approved and merged my code.
- Another coworker added the case that triggers the zero / infinity bug.
- My browser (Chromium-based Vivaldi) did not offer to stop the loop like Firefox used to do (TODO check if Firefox still does). (There is a task manager in the developer tools with an option to stop though.)
- The browser keeps reopening the same tab and executing the same cached front-end code after I stopped my preview server and also after I restarted the server with a code fix!
Solutions and follow-up Issues
Code more intelligently!
Not bad, but that's never guaranteed to prevent errors like that, as to err is human and it takes more than will power to increase intelligence.Write tests and test the tests! There are meta strategies like mutation testing. The challenge is not the testing itself, it's to learn how to architect your code so that it is testable.
What about tooling and static code analysis? This one wouldn't upset me that much if the linters didn't complain about anything. But often those "artficially intelligent" tools act even more unhelpfully by nagging about the wrong things (see my rant about linting the wrong code that I posted on the DEV blog last year).
What about browser safety? Crashing my browser with my own infinite loop on localhost is half as bad, but what if this was part of a malicious hacker scheme targeting customers in production? How to kill a distinct browser tab or stop a JavaScript process as a regular user with no knowledge about developer tools?
Resolutions
- learn to code better
- do more testing (unit testing my JavaScript functions, end-to-end testing web applications, testing the tests)
- open an eslint issue unless there already is one
- open a Chromium issue unless there already is one
- write about it on DEV.to ✔️
Posted on May 23, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.