There's a related trick I've recently begun using with progress bars which I plan to turn into a little JS library when I have time. Basically, watching a progress bar fill up makes time pass quickly, but making short-lived progress bars update asynchronously is a huge waste of time. You can use a spinner, but that's less effective. Alternatively, you can make the bar fill in a fixed amount of time, which is a problem if the operation takes longer than expected, because staring at a full progress bar makes time seem to pass even more slowly than nothing at all.
The solution I found was an exponential fill. Say you estimate an operation will take 4 seconds (this can even be hard coded). You show a bar that starts empty, and after 2 seconds, it is halfway full, after 4 seconds, 3/4 full, 6 seconds, 7/8, and so on until the operation completes and the bar disappears. That way, you never end up paused on a full progress bar, and you are still conveying a reasonable estimate to your user, and you never have to write another line of code to update a progress bar.
We did something similar for a search webpage. But with some query it could take too much and the slowing down of the bar filling wasn't well met with both our users and our boss.
We changed that with bogus writing under the progress bar.
The first bar had "searching" under it, and usually that was enough.
If it was still searching after the bar was at 100%, the bar would start the animation again and we would change the text with random stuff like ("building indexes","fetching images","generating tables",etc...).
> with some query it could take too much and the slowing down of the bar filling wasn't well met with both our users and our boss.
One idea I've toyed with, which adds some complexity, would be some random variation, so that you'd still get some faster jumps at the end, even though the average would be exponential.
The solution I found was an exponential fill. Say you estimate an operation will take 4 seconds (this can even be hard coded). You show a bar that starts empty, and after 2 seconds, it is halfway full, after 4 seconds, 3/4 full, 6 seconds, 7/8, and so on until the operation completes and the bar disappears. That way, you never end up paused on a full progress bar, and you are still conveying a reasonable estimate to your user, and you never have to write another line of code to update a progress bar.