Как синхронный однопоточный язык вообще может асинхронно выполнять задачи ?
В реальности он выполняет их поочередно, просто т.н. асинхронные операции, например промисы, выполняются не в общей очередности написанного кода, а ставятся в общую очередь и выполняются после того как выполнены синхронные операции.
Например
function fetchMe() {
fetch("/api/get").then(response => console.log("Сервер ответил " + response))
console.log("Ждем ответа сервера")
}
Первая строчка асинхронная, она не выполняется сразу а ставится в очередь. Вторая строчка выполняется сразу.
То что делает fetch - просто регулярно проверяет(в порядке общей очереди событий) ответил ли сервер и когда сервер ответил - выполняется код в then. Причем поскольку js синхронный, то если перед получением ответа сервера будет какая-то затратная операция, fetch будет терпеливо ждать и ответ вы получите не тогда, когда он реально пришел, а когда выполняемая функцией fetch периодическая проверка дождется своей очереди. Это и есть асинхронность в js.