It is one of the hardest things to get right in programming. and sometimes, like when you are waiting on a network and your connection is unreliable, just impossible.
It is hard because the blocking operation may be very deep in the call stack, and each element must collaborate. Not all APIs support asynchronous progress events. Proper progress bars are abstraction breakers. For example, your API may abstract away the fact you are on a network or doing things locally, except that if you want progress, these are very different cases, so you want to know the underlying situation. Ideally you should also know how good your connection is: an overcrowded airport Wi-Fi doesn't act the same as wired LAN.
UI/UX people can only do with what their back-end provides. The back-end can only do with what the APIs they use provide. The APIs can only do with what the system provides. So sometimes, a spinner is the only thing that can be done within a reasonable budget.
It is hard because the blocking operation may be very deep in the call stack, and each element must collaborate. Not all APIs support asynchronous progress events. Proper progress bars are abstraction breakers. For example, your API may abstract away the fact you are on a network or doing things locally, except that if you want progress, these are very different cases, so you want to know the underlying situation. Ideally you should also know how good your connection is: an overcrowded airport Wi-Fi doesn't act the same as wired LAN.
UI/UX people can only do with what their back-end provides. The back-end can only do with what the APIs they use provide. The APIs can only do with what the system provides. So sometimes, a spinner is the only thing that can be done within a reasonable budget.