Асинхронное исполнение кода позволяет более эффективно использовать процессорное время.
Если взять синхронный сценарий исполнения, то какое-то время поток приложения загружает процессор работой, далее обычно наступает ситуация, когда поток приложения ждет завершения какой-то операции ввода\вывода. Это может быть ожидание срабатывания таймера, ожидание данных от сетевой карты, ожидание пользовательского ввода и т.п. Пока происходит ожидание поток приложения не использует процессор. В некоторых случаях это нас устраивает, если другой полезной работы мы не можем совершить. В других ситуациях мы хотим одновременно что-то делать, например иметь возможность обрабатывать клики мышкой пользователя в то время как идет запрос к БД, например.
Тогда мы задействуем асинхронный подход. В этом случае когда поток приложения доходит до ожидания окончания операции ввода\вывода, он не ждет а может быть использован для другой работы, а в момент когда закончится операция ввода\вывода и поток не будет занят другой работой, он сможет продолжить исполнение кода с того места на котором остановился.
Также есть и другое понятие асинхронности, также его называют отложенным исполнением. Это ситуация когда данные обрабатываются не во время запроса пользователя, а данные быстро буферируются на диске в БД или очереди и мы быстро отвечаем пользователю. А в этот момент асинхронный воркер циклично обрабатывает этот буфер, например уменьшает картинки, или перекодирует видео или считает какую-то агрегацию.