Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

[Projeto] Exercício: Contagem regressiva recursiva

import { createInterface } from "readline";

const rl = createInterface({
  input: process.stdin,
  output: process.stdout,
});

const perguntar = (pergunta) => {
  return new Promise((resolve) => {
    rl.question(pergunta, resolve);
  });
};

const validarNum = (input) => {
  const num = Number(input);

  if (Number.isNaN(num) || !Number.isInteger(num) || num < 1) return null;
  return num;
};

const tratarInvalido = (dado) => {
  if (dado === null) {
    rl.close();
    throw new Error("Entrada inválida");
  }
  return dado;
};

const contagemRegressiva = (num) => {
  console.log(num);
  return num === 1 ? "Lançamento!" : contagemRegressiva(num - 1);
};

const main = async () => {
  try {
    console.log("CONTAGEM REGRESSIVA");

    const num = tratarInvalido(validarNum(await perguntar("Número inicial: ")));

    console.log(contagemRegressiva(num));
  } catch (err) {
    console.log(err.message);
  } finally {
    rl.close();
  }
};

main();
1 resposta
solução!

Olá, Vitor. Como vai?

Gostaria de parabenizar pela sua solução! O seu código está excelente e demonstra um ótimo domínio da linguagem JavaScript. Você aplicou muito bem conceitos importantes, como a criação de Promises para lidar com a leitura de dados de forma assíncrona, o uso de async/await e o tratamento de erros estruturado com blocos try/catch/finally. A separação do código em funções menores e de responsabilidade única (validarNum, tratarInvalido e perguntar) é uma ótima prática que deixa o código muito mais legível e fácil de dar manutenção.

Falando especificamente sobre a função contagemRegressiva, ela implementa perfeitamente os dois pilares de uma recursividade segura:

  • O caso base, que é a condição de parada: num === 1 retornando "Lançamento!".
  • O passo recursivo, que altera o estado aproximando do caso base e chama a função novamente: contagemRegressiva(num - 1).

Como um complemento ao seu aprendizado, vale a pena entender como o motor do JavaScript lida com essa recursão por trás dos panos usando a Call Stack (Pilha de Chamadas). Se o usuário digitar o número 3, a execução ocorre desta forma:

  1. A função contagemRegressiva(3) é chamada, imprime 3, e fica na memória aguardando o retorno de contagemRegressiva(2).
  2. A função contagemRegressiva(2) é chamada, imprime 2, e fica na memória aguardando o retorno de contagemRegressiva(1).
  3. A função contagemRegressiva(1) é chamada, imprime 1, atinge o caso base e retorna a string.
  4. A string é passada de volta desempilhando todas as chamadas anteriores até chegar no seu console.log dentro do bloco main.

Um detalhe técnico importante sobre a recursão é que ela consome espaço na memória para cada função empilhada. Se um usuário digitasse um número gigantesco (por exemplo, 100000), a pilha encheria completamente e o Node.js lançaria um erro conhecido como RangeError: Maximum call stack size exceeded (estouro de pilha). Em cenários do mundo real onde sabemos que a quantidade de repetições será massiva, usar laços convencionais como for ou while evita o consumo da pilha. No entanto, para o seu exercício e para operações com limites controlados, a recursividade é uma solução muito elegante.

Continue praticando dessa forma, construindo códigos limpos e bem validados!

Espero que possa ter lhe ajudado!