Acho que a discussão precisa começar com a definição do que significa ser assíncrono. Me parece que todos os comentários abaixo estão falando sobre o mesmo assunto, mas discordam sobre o que significa ser assíncrono. A especificação do ECMAScript (o nome oficial do JavaScript) menciona suas capacidades para desenvolver funções assíncronas, bem como para interagir com elas. https://tc39.es/ecma262/ Então, talvez a discussão aqui deva ser sobre o que uma linguagem precisa ter para ser considerada assíncrona.

Gostaria de pedir que o autor, ou outros que defendem que ela não é ou não suporta funções assíncronas, apresentem:

  1. A definição do que significa ser assíncrono e
    1. Um exemplo de uma outra linguagem que é considerada assíncrona e que faz algo que não pode ser reproduzido em JavaScript com suas bibliotecas padrão.

Acho que isso ajudaria no entendimento.

Obrigado

Cristian, claramente o autor do post está confuso no conceito do que é ser assíncrono. A definição foi colocada explicitamente ou implicitamente em outros comentários, não tem muito o que discutir.

O que eu acho que ele realmente está querendo dizer é sobre concorrência ou paralelismo na execução das threads.

No entanto, o Javascript (que quer dizer mais sobre sintaxe aqui) nem deveria entrar em discussão, pois seguindo a especificação do ECMAScript que você mesmo compartilhou, há os "motores" responsáveis por implementar isso e aí temos uma gama completa de implementações para usos diferentes.

O que eu tentei argumentar com o autor é que ele está discutindo algo que conceitualmente estava errado desde o início, todo o resto é consequência disso.

Sim, elixir/Erlang, go, v todas possuem greenthreads roda em uma única cpu, porém roda assíncronamente.

Tenho duas fontes, uma com um exemplo dado por Fabio Akita em vídeo: The Elixir of Life por Fabio Akita - DevInSantos 2015

E a outra é uma pergunta feita no site o Elixir: How are Elixir processes lightweight?

Não é que sou hate de javascript não, tem seus pontos negativos, mas não é um problema pra mim, além de ter me feito sentido o que foi dito no post original eu lembrei desse vídeo acima onde explicava isso.

E agradeço por sua forma serena de alcamar os animos de todos.

Obrigado pela resposta! O vídeo me ajudou a compreender melhor. Acho que a confusão é em distinguir entre multithreading e assincronia. No vídeo, se eu entendi direito, ele menciona que Elixir é multithread e, como você disse, usa green threads. Já o JavaScript não é multithread, mas isso não significa que não seja assíncrono. No exemplo do vídeo, ele é injusto com o JavaScript, pois utiliza uma função sleep bloqueante, que nao é parte da linguagem,mas uma biblioteca que ele installou, enquanto em Elixir ele usa uma função não bloqueante (de acordo com ele mesmo). Se ele usasse uma função bloqueante em Elixir e forçasse a execução em uma única thread, teria o mesmo problema. Se esse é o caso e o JavaScript executa código assíncrono, então, desde que a função seja não bloqueante como a do exemplo em Elixir, deveria ser possível reproduzir o mesmo comportamento e realizar 400 chamadas em 4 segundos, correto? Decidi tentar! :) Abaixo está a minha reprodução do código do vídeo usando a mesma função bloqueante. ``` var express = require("express"); var router = express.Router(); router.get("/", function (req, res) { require("sleep").sleep(1); res.json({ message: "Hello World!" }); }); module.exports = router; function startServer() { var app = express(); app.use(router); app.listen(3002); console.log("Server started at http://localhost:3002"); } startServer(); ``` E aqui está o resultado ``` Javascript Async siege -r 1 -c 10 http://localhost:3002 ** SIEGE 4.1.6 ** Preparing 10 concurrent users for battle. The server is now under siege... HTTP/1.1 200 1.02 secs: 26 bytes ==> GET / HTTP/1.1 200 2.03 secs: 26 bytes ==> GET / HTTP/1.1 200 3.03 secs: 26 bytes ==> GET / HTTP/1.1 200 4.04 secs: 26 bytes ==> GET / HTTP/1.1 200 5.05 secs: 26 bytes ==> GET / HTTP/1.1 200 6.05 secs: 26 bytes ==> GET / HTTP/1.1 200 7.05 secs: 26 bytes ==> GET / HTTP/1.1 200 8.06 secs: 26 bytes ==> GET / HTTP/1.1 200 9.06 secs: 26 bytes ==> GET / HTTP/1.1 200 10.07 secs: 26 bytes ==> GET / Transactions: 10 hits Availability: 100.00 % Elapsed time: 10.07 secs Data transferred: 0.00 MB Response time: 5.55 secs Transaction rate: 0.99 trans/sec Throughput: 0.00 MB/sec Concurrency: 5.51 Successful transactions: 10 Failed transactions: 0 Longest transaction: 10.07 Shortest transaction: 1.02 ``` Usando uma função bloqueante, consegui reproduzir a mesma lentidão mostrada no vídeo. Agora, veja o que acontece se eu usar uma função sleep que não bloqueia: ```javascript var express = require("express"); var router = express.Router(); function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } router.get("/", function (req, res) { // require("sleep").sleep(1); sleep(1000).then(() => { res.json({ message: "Hello World!" }); }); }); module.exports = router; function startServer() { var app = express(); app.use(router); app.listen(3002); console.log("Server started at http://localhost:3002"); } startServer(); ``` Resultado: ``` (base) ➜ Javascript Async siege -r 1 -c 10 http://localhost:3002 ** SIEGE 4.1.6 ** Preparing 10 concurrent users for battle. The server is now under siege... HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.02 secs: 26 bytes ==> GET / HTTP/1.1 200 1.02 secs: 26 bytes ==> GET / HTTP/1.1 200 1.02 secs: 26 bytes ==> GET / Transactions: 10 hits Availability: 100.00 % Elapsed time: 1.02 secs Data transferred: 0.00 MB Response time: 1.01 secs Transaction rate: 9.80 trans/sec Throughput: 0.00 MB/sec Concurrency: 9.93 Successful transactions: 10 Failed transactions: 0 Longest transaction: 1.02 Shortest transaction: 1.01 ``` Observe que cada requisição levou cerca de 1 segundo, e o tempo total foi 1.02 segundos. Posso até reproduzir o teste mais pesado do vídeo, com 2 repetições e 200 usuários paralelos: ``` (base) ➜ Javascript Async siege -r 2 -c 200 http://localhost:3002 ** SIEGE 4.1.6 ** Preparing 200 concurrent users for battle. The server is now under siege... HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / HTTP/1.1 200 1.01 secs: 26 bytes ==> GET / .... HTTP/1.1 200 1.02 secs: 26 bytes ==> GET / HTTP/1.1 200 1.02 secs: 26 bytes ==> GET / Transactions: 400 hits Availability: 100.00 % Elapsed time: 2.08 secs Data transferred: 0.01 MB Response time: 1.03 secs Transaction rate: 192.31 trans/sec Throughput: 0.00 MB/sec Concurrency: 197.96 Successful transactions: 400 Failed transactions: 0 Longest transaction: 1.06 Shortest transaction: 1.00 ``` Note como as requisições individuais continuam em torno de 1 segundo, e o total é 2.08 segundos, mais rápido que Elixir no vídeo. Com relação ao primeiro ponto, o JavaScript roda código assíncrono e consegue responder a chamadas em paralelo, mesmo usando uma única thread. No entanto, é importante lembrar que, se o código for escrito de forma síncrona, ele não será executado de maneira assíncrona. Cabe ao desenvolvedor garantir que o código seja escrito para rodar assincronamente. Quando o JavaScript encontra funções assíncronas por natureza, como operações de I/O, ele retorna a execução para o fluxo principal do código, permitindo que outras instruções continuem sem esperar. Porém, se o código nunca chegar a uma função assíncrona, ele será executado de forma totalmente síncrona. No meu código acima, essa função assíncrona é o setTimeout. Em algumas linguagem como Python, o desenvolvedor tem que fazer isto explicitamente. JavaScript se destacou justamente por facilitar a execução de funções de I/O, como leitura de arquivos e chamadas de rede de maneira assíncrona, permitindo que o código continue avançando sem esperar pela resposta do servidor remoto. O que JavaScript não faz é executar código em paralelo. Todo o código roda em uma única thread e em um event loop. Portanto, se houver algo pesado para processar, como uma grande quantidade de dados, o JavaScript ficará limitado pela capacidade dessa única thread. Me fale se o que escrevi faz sentido. Estou curioso para saber se consegui entender seu ponto e se estamos alinhados na diferença entre assíncrono e paralelo.
Cristian, macho eu criei alguns exemplos pra te dá sobre greenthread e goroutines e testei iria trazer o exemplo dos resultados quando eu percebi que o meu conhecimento de relacionado a threads estava fraco, pois acabava que não batia quando realizava o teste era muita teoria, e teoria equivocada. E reconheço a minha confusão, peço desculpas e obrigado por sua paciência em explicar.