You've heard it a hundred times !
The second thing you should study in Arduino software development...
After setup() and loop() blinking a LED using delay().
Do your homework on using millis() for timing and delays !
Once you master this relatiely simple programming concept, your projects will buzz along - and you'll wonder how you got by without it...
delay() is 'ok' in some rare cases, and often seen in setup() where steps need to be completed in sequence - but once your program is off and running - if it's meant to do somethnig meaningful, and be responsive - delay and closed loops become an obstacle to good programming and an interactive experience.
The concept you need to understand is 'blocking' vs 'non-blocking' program execution.
I could write another treatise - but here's a decent explanation...
Ref written by [nadroj] with edits.
Blocking and non-blocking are just logical names to describe the behaviour of program blocks.
As the name implies, a blocking function blocks the calling function. This means the caller does not do anything until the blocking function returns control.
You can consider this synchronous behaviour, because the interactions are "synchronized" in that the calling function must wait until the called blocking function is finished before continuing.
Conversely, non-blocking functions, of course, do the opposite: they do not require the caller to wait until they're finished.
They simply perform the function, then immediately continue to the next part of the program.
This could be considered "asynchronous" of program elements.
Think of an in-person conversation with someone as asynchronous.
Each person doesn't necessarily wait until the other is finished their sentence.
In a formal conversation with your boss, you're more likely to communicate synchronously: you don't want to interrupt while your boss is talking!
You wait for him/her to finish talking (blocking), then you talk.