Fiz alguns testes aqui, só fiz uma pequena modificação no código, inicializando o n com um BigInt também:

let n = 1000000n; // sufixo "n" faz com que seja BigInt
let a = BigInt(0), b = BigInt(1);
for (let i = BigInt(0); i < n; i++) {
  [a, b] = [b, a + b];
}
console.log(a);

Testei na minha máquina (Ubuntu 22.04.3, processador 11th Gen Intel® Core™ i5-1145G7 2.60GHz, 8 núcleos), primeiro com o teste mais básico, usando o comando time do Linux. Ou seja, time bun run arquivo.js e time node arquivo.js. A versão do Node é v18.17.1, e do Bun é 1.0.1. Os resultados estão abaixo (lembrando que em outros hardwares os tempos poderão ser diferentes, obviamente), só retirei a saída do console.log para não deixar poluído.

Node:

real    0m10,368s
user    0m8,712s
sys     0m0,037s

Bun:

real    0m9,915s
user    0m9,782s
sys     0m1,833s

O que importa é a primeira linha ("real", o tempo que efetivamente se passou entre eu teclar ENTER e o comando terminar).

Só de curiosidade, "user" é o tempo de CPU em user mode (fora do kernel), e "sys" é o tempo de CPU dentro do kernel (em chamadas de sistema, por exemplo). Mas estes tempos são computados considerando todos os núcleos, então se a máquina tem mais de um, a soma de "user" e "sys" pode ser maior que "real", conforme explicado aqui.

Enfim, no meu caso o Node demorou um pouco mais, mas dado o tempo total de ambos (10,3 segundos versus 9,9 segundos), não acho que foi uma diferença tão significativa (cerca de 4% a mais).


Mas tem um detalhe, operações de I/O (como o console.log) costumam ser caras e elas geralmente acabam mascarando o resultado (neste caso nem tanto porque só tem uma, mas enfim). Então removi o console.log para ver apenas o tempo do loop e rodei de novo.

Node:

real    0m8,615s
user    0m8,577s
sys     0m0,033s

Bun:

real    0m9,329s
user    0m9,424s
sys     0m1,710s

Agora o Bun foi ligeiramente mais lento, mas novamente, não acho que a diferença é tão significativa.

Testei mais algumas vezes, e às vezes o Node era mais rápido, às vezes era mais lento, mas sempre com diferenças pequenas. Nada tão gritante quanto o que vc encontrou.


Uma maneira melhor de testar

O problema de fazer um teste isolado é justamente esse: vc roda uma vez um pequeno trecho de código e já acha que é o suficiente, mas conforme já visto aqui, isso pode levar a conclusões precipitadas.

Mesmo que rode várias vezes, podem ter outros fatores que influenciam, como outros processos rodando na mesma máquina (ainda mais se tiver I/O e outras operações bloqueantes), e até mesmo a própria inicialização do runtime (tanto o Node quanto o Bun precisam de uma etapa de inicialização antes de começar a rodar o código propriamente dito).

Sendo assim, uma forma melhor de testar seria usar uma lib específica que desconsidera esses fatores externos. Eu usei o Benchmark.js, o código ficou assim:

var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;

suite.add('test', function () {
    let n = 1000000n;
    let a = BigInt(0), b = BigInt(1);
    for (let i = BigInt(0); i < n; i++) {
      [a, b] = [b, a + b];
    }
}).on('cycle', function (event) {
    console.log(String(event.target));
}).run({
    'async': true
});

Obs: o propósito do Benchmark.js na verdade é comparar dois códigos diferentes. Por exemplo, chamo várias vezes add com algoritmos diferentes, e no final ele mostra qual é mais rápido. Mas aqui eu coloquei apenas um, e rodei este teste no Node e depois no Bun, pois ele também mostra a quantidade de operações por segundo que conseguiu executar. E é exatamente isso que eu quero comparar, pois dá para ter uma ideia melhor do desempenho de cada um.

Resultados com Node:

test x 0.12 ops/sec ±0.24% (5 runs sampled)

E com Bun:

test x 0.11 ops/sec ±0.90% (5 runs sampled)

Ou seja, 0,12 operações por segundo versus 0,11 operações por segundo. Em outras palavras, no Node demoraria cerca de 8,3 segundos para rodar o código uma vez, e no Bun, cerca de 9 segundos. Mais uma vez, uma diferença bem pequena, nada da discrepância que vc encontrou.

Rodei mais algumas vezes e os resultados giraram em torno disso, com pouca variação, e às vezes um era melhor, às vezes o outro - o que mostra que mesmo uma lib que desconsidera fatores externos não consegue eliminar 100% deles.


Quanto ao segundo caso (o console.log dentro do loop), realmente o Node foi pior em todos os casos. Primeiro com time, segue abaixo.

Bun:

real    0m2,648s
user    0m0,656s
sys     0m1,416s

Node:

real    0m5,264s
user    0m4,276s
sys     0m0,884s

E com o Benchmark.js:

Bun:

test x 0.38 ops/sec ±2.40% (5 runs sampled)

Node:

test x 0.19 ops/sec ±7.30% (5 runs sampled)

Ou seja, o Bun foi cerca de duas vezes mais rápido, uma diferença maior que no primeiro código.

Pesquisei um pouco a respeito e encontrei isso, que indica que a implementação do console.log no Node acaba deixando-o pior para este caso específico.


Conclusões (ou não)

No fim das contas, é difícil tirar conclusões definitivas sobre qual deles sempre será mais rápido. Isso depende de tantos fatores que o melhor a fazer é testar em uma situação mais próxima possível do caso concreto: teste o seu sistema, com seu código e seus casos de uso, e veja se faz diferença. Testar rodando um código qualquer uma ou poucas vezes é o teste mais ingênuo e propenso a erros que vc pode fazer (e tirar "verdades" disso é pior ainda). Testar a situação real costuma ser mais efetivo, pois aí vc está considerando o seu contexto específico em vez de só seguir a moda. Mais ainda, como vimos acima, em um caso particular pode fazer mais diferença que em outros, então o melhor é testar com o código que vc efetivamente vai usar.

Se procurar por benchmarks que comparam os dois, vai encontrar vários diferentes, e é importante ver qual código foi usado para testar, já que isso pode fazer diferença. E claro que também precisa considerar outros fatores: se usar A ou B vai facilitar o dia-a-dia da sua equipe, se é estável, se aguenta o tranco, etc etc etc. Vc pode inclusive concluir que não faz diferença, e não tem problema, pois o que importa é que seja uma decisão embasada, em vez de só puro achismo ou "ouvi dizer que é melhor".

Exato! Foi um typo porque eu reescrevi o Fibonacci enquanto postava aqui :) b = BigInt(1)

PRIMEIRAMENTE: MUITO MASSA A TUA ANALISE! Eu vou postar um video amanhã sobre e vou colocar o link do TabNews nele porque acredito que até amanhã conseguimos chegar na conclusão do porque o NodeJS performa muito mais rapido que o Bun (todas as vezes aqui) no meu ambiente com um MacOS M1 Max. Não usei nenhuma biblioteca, apenas usei de fato o console.log e um console.time.

Eu vou rodar o Benchmark.Suite; aqui e postar como que ficou no M1.

O resultado aqui no **M1 Max** foi bem diferente. ``` rinha % bun execute.js test x 3.80 ops/sec ±5.63% (14 runs sampled) rinha % node execute.js test x 12.14 ops/sec ±3.39% (35 runs sampled) ``` Rodei multiplas vezes em todas o bun ficava em 3-4 ops/sec enquanto o Node ficava em 11-12 ops/sec, confirmando que no meu **M1 Max** rodando o mesmo teste que você o Node performou 3x-4x mais rapido que bun. Seria interessante alguem com **Apple Chip M1** fazer o mesmo testes, e talvez alguem com MacOs Intel Chip.
Eu tenho um MacBook antigo (2012), processador 2.6 GHz Quad-Core Intel Core i7, e refiz o teste nele com as mesmas versões (Node 18.17.1 e Bun 1.0.1). Agora a diferença foi bem maior no código que calcula Fibonacci. Primeiro com `time`: Node: ``` real 0m9.818s user 0m9.412s sys 0m0.443s ``` Bun: ``` real 0m33.275s user 0m33.062s sys 0m3.324s ``` E com o Benchmark.js: Node: ``` test x 0.14 ops/sec ±1.67% (5 runs sampled) ``` Bun: ``` test x 0.03 ops/sec ±0.36% (5 runs sampled) ``` --- Já com o segundo código (`console.log` dentro do *loop*), a situação se inverte e o Bun se mostra mais rápido. Primeiro com `time`: Node: ``` real 0m12.736s user 0m10.322s sys 0m1.732s ``` Bun: ``` real 0m5.140s user 0m2.289s sys 0m1.335s ``` E com o Benchmark.js: Node: ``` test x 0.09 ops/sec ±0.15% (5 runs sampled) ``` Bun: ``` test x 0.21 ops/sec ±0.15% (5 runs sampled) ``` Provavelmente por causa [do que já mencionei](https://stackoverflow.com/q/6853566), de que a implementação do `console.log` no Node piora bastante a performance. No primeiro código não causa problema porque é só uma chamada no final e o grosso do trabalho é no cálculo, mas no segundo já faz diferença. --- Curiosamente, se não usar `BigInt`, aí muda de novo: ```javascript // diminuí o n para não estourar o valor máximo de Number let n = 1000; let a = 0, b = 1; for (let i = 0; i < n; i++) { [a, b] = [b, a + b]; } ``` Usando este código, o Bun foi **muito** mais rápido que o Node, tanto no Mac quanto no Linux (em média cerca de 10 vezes mais rápido).
só que usando esse codigo tu nao chega em `n` de 100.000 imagina 1.000.000 haha BigInt parece ser uma limitação do bun atual, sobre o `console.log` se nao me engano ele vai direto pra API nativa no V8, provavelmente aqui temos uma diferença do Zig no bun?
Bom, a ideia era eliminar o uso de `BigInt` pra ver se mudava alguma coisa, então o jeito foi diminuir o valor. Mas se somente o `BigInt` fosse o problema, então daria diferença no Linux também, mas aqui deu "empate técnico". Talvez seja a combinação `BigInt` + Mac que cause essa perda de desempenho, fica aí a questão pra uma futura investigação :-) Também pensei se a desestruturação faz alguma diferença, fica aí outra sugestão de teste também (usar atribuições simples em vez de `[a, b] = [b, a + b]`).
Bom, fiz o teste comparando os algoritmos com e sem desestruturação, e também com e sem `BigInt`: ```javascript var Benchmark = require('benchmark'); var suite = new Benchmark.Suite; suite .add('desestruturação', function () { const n = 1000; let a = 0, b = 1; for (let i = 0; i < n; i++) { [a, b] = [b, a + b]; } }) .add('sem desestruturação', function () { const n = 1000; let a = 0, b = 1; for (let i = 0; i < n; i++) { let tmp = a; a = b; b += tmp; } }) .add('desestruturação BigInt', function () { const n = 1000000n; let a = 0n, b = 1n; for (let i = 0n; i < n; i++) { [a, b] = [b, a + b]; } }) .add('sem desestruturação BigInt', function () { const n = 1000000n; let a = 0n, b = 1n; for (let i = 0n; i < n; i++) { let tmp = a; a = b; b += tmp; } }) .on('complete', function () { console.log('Fastest is ' + this.filter('fastest').map('name')); }) .on('cycle', function (event) { console.log(String(event.target)); }) .run({ 'async': true }); ``` Testei só no Linux, porque no Mac já vimos que `BigInt` fica bem mais lento usando o Bun. Resultados (em operações por segundo, ou seja, **quanto mais, melhor**): | Teste | Node | Bun | |------------------------------|-----------|-----------| | desestruturação | 236.387 | 3.920.325 | | sem desestruturação | 1.085.075 | 3.897.458 | | desestruturação `BigInt` | 0,11 | 0,11 | | sem desestruturação `BigInt` | 0,12 | 0,11 | Ou seja, parece que a implementação da desestruturação no Bun é mais rápida que no Node. Basta ver que sem desestruturação e sem `BigInt`, o Node pulou de 236 mil para 1 milhão de operações por segundo (e mesmo assim não chegou perto do Bun). Mas quando `BigInt` é usado, a diferença já não foi tão grande. Imagino que neste caso o *overhead* dos cálculos parece ter um impacto maior que a desestruturação.
Intrigante o resultado, o Bun é feito com o motor WebPack, que roda no Safari, ao invés do V8. Teoricamente o Bun deveria ir melhor no hardware da Apple, já que utiliza um recurso que a própria Apple utiliza e provavelmente otimiza por padrão. Outro adendo importante é que o Bun recomenda que esses tipos de teste em apps cli sejam feitos com o [hyperfine](https://github.com/sharkdp/hyperfine)
Vou compartilhar o resultado do benchmark com o M1 Pro: ``` ~/projects/bun-benchmark  node index.js test x 0.17 ops/sec ±2.08% (5 runs sampled) ~/projects/bun-benchmark  bun index.js test x 0.07 ops/sec ±1.74% (5 runs sampled) ``` Executei o teste algumas vezes, e em todas elas, o node foi em média 2x mais rápido. De fato, parece que o node é mais rápido no M1/M1 Pro (e ainda melhor no M1 Max), porém mais lento (ou praticamente igual) no Intel.
isso é muito louco porque é o oposto que eu imaginaria, pelo fato do bun usar runtime com engine do "safari"
> Eu vou postar um video amanhã sobre e vou colocar o link do TabNews nele Opa, que bom que avisou sobre o vídeo dessa vez! hahaha Pra aguentar o volume de acessos vindos pelo seu vídeo, já vou trocar aqui o Node pelo Bun no TabNews... 😜 Não, péra! Vendo os comparativos, é melhor adicionar uns pentes de memória e trocar o HD por SSD pra dar um gás no servidor 🤣🚀 Falando sério agora... É muito massa que sempre vem um pico de acessos e de novos cadastros quando você fala do TabNews nos seus vídeos. 💪🚀