JS é sim assíncrono -> ele permite continuar a execução do código depois de fazer uma operação bloqueante
Mais ou menos, a linguagem em si não permite, o que javascript faz é um truque que até daria pra fazer em PHP mas fica extremamente lento, mas porque javascript NÃO É assincrono, o objeto Promisse nada mais é que essas bibliotecas PHP pré carregadas no Javascript, o que Javascript faz é um tipo de corroutina onde yeld e resume não devolvem nem injetam valores, quando você faz:
async function fn() {
console.log(1);
console.log(2);
console.log(3);
console.log(4);
}
É como se estivesse (não é mas na prática...) fazendo:
function *fn() {
console.log(1);
yeld;
console.log(2);
yeld;
console.log(3);
yeld;
console.log(4);
yeld;
}
E o looping principal vai checkando se consegue resumir, ou seja, é um código efetivamente sincrono com uma pequena trapaça
Agora observe como funciona quando a linguagem não consegue injetar os pontos de parada:
async function x() {
const _ = await new Promise(resolve => setTimeout(() => {
alert("Olá!");
resolve();
}, 0));
}
console.log("inicio");
await x();
console.log("fim");
As requisições em Javascript parecem funcionar de forma assincrona porque fazem a colheita enquanto o resto do código, incusive se você adicionar uma função bloqueadora pode resultar em erros de timeout nas requisições assincronas, em resumo javascript se comporta visualmente de maneira assincrona porque APIs externas igual as bibliotecas externas PHP fazem essa pausa e peritem ser resumidas, async e await são açucar sintatico apenas