It might be worth it to read this:
Concurrency model and the event loop - JavaScript | MDN[
^]
Basically your solution of using setTimeout should work something like
this CodePen[
^], if you compare that to your attempt at using set timeout I think you'll find you probably accidentally moved the code setting the class inside the setTimeout event handler - if not you should post that code as well.
The problem you're have can be explained by how browsers render the page. Essentially the browser is single threaded, and the browser rendering is paused while your code is executing, and will do all updates after your code finishes running.
The reason calling set timeout for a single millisecond works, is that it finishes executing your code for the browser to run one render pass, and then executes the timeout event as soon as the render has completed.