Não, Javascript não é assincrono
Eu postei um comentário nesse post respondendo a afirmação que "PHP não é asíncrono, assim não tem Promise." com um exemplo de porque a afirmação de ter Promise não torna uma linguagem assincrona e fui trucidado nos downvotes, tanto que tive que apagar pra proder comentar, então logo de cara, não, ter Promisse não torna nada assincrono, Promisse é Promisse, assincrono é assincrono, por exemplo, um mecanismo simples de Promisse em PHP:
<?php
class Promise {
public $status;
public $resolved;
public $rejected;
public $result;
private static $deadPromises = 0;
public static $promisesList = [];
private $generator;
public function __construct($generatorFunction){
$this->status = "pending";
$this->generator = $generatorFunction();
self::$promisesList[] = $this;
$this->resume();
}
public function resume() {
if ($this->status != "pending") return;
try {
// Check if the generator is valid and proceed
if ($this->generator && $this->generator->valid()) {
$this->generator->next();
} else {
$this->status = "resolved";
self::$deadPromises++;
}
} catch (Exception $e) {
self::$deadPromises++;
$this->status = "rejected";
}
}
static public function iterate() {
while (true) {
foreach (Promise::$promisesList as $promise) {
$promise->resume();
}
if (Promise::$deadPromises == count(Promise::$promisesList)) {
break;
}
}
}
}
function foreachGenerator($arr, $callback) {
foreach ($arr as $key => $value) {
$callback($key, $value);
yield; // Yield here to pause after each callback execution
}
}
// Main execution
echo "Inicio do loop principal<br>";
$p = new Promise(function () {
return foreachGenerator([1, 2, 3, 4, 5, 6], function ($i, $v) {
echo "$v<br>";
});
});
echo "Fim do loop principal<br>";
// Loop das promisses
Promise::iterate();
?>
Nenhuma biblioteca extra, só PHP puro e a saída foi:
Inicio do loop principal
1
2
Fim do loop principal
3
4
5
6
Acabei de implementar um mecanismo de Promise em PHP, e PHP continua sincrono, qual o truque?
Javascript e sua forma de execução
Javascript executa as instruções linha a linha em uma única pilha de execução quando você faz:
console.log("Inicio");
p = (new Promise(() => { console.log("meio?");}));
console.log("Fim");
Javascript executa o primeiro console.log
e vai para a próxima linha, só que nessa linha tem a declaração de uma Promise, uma Promise nada mais é que uma operação (e chamar uma função é uma operação) que pode ser concluída agora, depois ou nem ser concluida, é uma "promessa" como o nome sugere, então o que JS faz é executar essa função e se ela pausar sua execução por algum motivo, o interpretador segue para a próxima linha, que no caso é outro console.log
, mas ele não só ignora ela, ele armazena essa Promise, depois que tudo que não for executado, o interpretador põe cada uma das promises que você declarou na pilha de execução e vai verificando o estado, enquanto estiver pending
ela despausa a execução e segue para a próxima até que todas ou tenham como o estado seja fulfilled
ou rejected
, quando o estado mudar para um desses dois ela chama a função callback
que você passou em then
e catch
respectivamente
Tirando a prova
Você pode ainda estar revoltado comigo achando que eu estou inventando que quero te enganar mas se liga só:
console.log("Inicio");
function* gerador1() {
let n = -1;
while (n < 10) {
n+=2;
yield n;
}
}
function* gerador2() {
let n = 0;
while (n < 10) {
n+=2;
yield n;
}
}
const p1 = new Promise((resolve) => {
const generator = gerador1();
const interval = setInterval(() => {
const next = generator.next();
if (next.done) {
clearInterval(interval);
} else {
console.log(next.value);
}
}, 1);
});
const p2 = new Promise((resolve) => {
const generator = gerador2();
const interval = setInterval(() => {
const next = generator.next();
if (next.done) {
clearInterval(interval);
} else {
console.log(next.value);
}
}, 1);
});
console.log("Fim");
Ao colar isso no console do navegador, você verá a saída:
Inicio
Fim
undefined
1
2
3
4
5
6
7
8
9
10
11
O undefined
indica que a pilha de execução linha a linha seguiu conforme previsto, e a sequência de 1 a 11 demostra que p1
e p2
foram alternadas também conforme previsto, uma linguagem verdadeiramente assincrona possui mais de uma pilha de execução o que não é o caso de JS, e pilhas de execução não são threads diferente, então resumindo, assincronismo em JS é apenas uma ilusão de percepção, muito bem feita mas umas ilusão, um último exemplo caso por qualquer motivo que seja você ainda dúvide que JS é sincrono e assincronismo não é um truque:
function* gerador1() {
let n = -1;
while (n < 10) {
n+=2;
yield n;
}
}
const p1 = new Promise((resolve) => {
const generator = gerador1();
const interval = setInterval(() => {
const next = generator.next();
if (next.done) {
clearInterval(interval);
resolve("Sequence complete");
} else {
console.log(next.value);
}
}, 500);
});
const p2 = new Promise((resolve) => {
const generator = gerador1();
const interval = setInterval(() => {
const next = generator.next();
if (next.done) {
clearInterval(interval);
} else {
alert(`P1 não executa até o fim já que a pilha é a mesma :) e eu bloqueio a pilha, para P1 executar eu preciso liberar a pilha`);
}
}, 500);
});
Como agora da pra notar, o que Javascript tem são açúcares sintáticos setInterval
nada mais faz que executar a função passada como argumento, bloqueando a pilha de execução, e bloqueando liberando a pilha pelo tempo especificado, ou seja, não é assincronismo, mas dá pra fazer assincronismo real em javascript, mas aí, assim como PHP dependem de extensões, não é mais o foco