Semana 2: JavaScript Assíncrono

Promises, Async/Await, Módulos Nativos do Node.js e Express.js

🎯 Objetivo: Dominar programação assíncrona, explorar módulos nativos do Node.js e criar seu primeiro servidor Express

📊 Seu Progresso

0% concluído

1

Nível Básico

JavaScript Assíncrono: Promises e Async/Await

🤝 Promises Avançadas

Vamos aprofundar o conhecimento em Promises e aprender métodos avançados como Promise.all() e Promise.race()!

📝 Exemplo Prático:

// 1. Promise.all() - Executa múltiplas promises em paralelo
function buscarUsuario(id) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({ id, nome: `Usuário ${id}`, email: `user${id}@email.com` });
        }, Math.random() * 1000 + 500);
    });
}

function buscarPosts(userId) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve([
                { id: 1, titulo: 'Post 1', userId },
                { id: 2, titulo: 'Post 2', userId }
            ]);
        }, Math.random() * 1000 + 300);
    });
}

function buscarComentarios(postId) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve([
                { id: 1, texto: 'Ótimo post!', postId },
                { id: 2, texto: 'Muito útil!', postId }
            ]);
        }, Math.random() * 800 + 200);
    });
}

console.log('=== DEMONSTRAÇÃO DE PROMISE.ALL ===');

// Executando múltiplas operações em paralelo
const promises = [
    buscarUsuario(1),
    buscarUsuario(2),
    buscarUsuario(3)
];

Promise.all(promises)
    .then(usuarios => {
        console.log('✅ Todos os usuários carregados:');
        usuarios.forEach(user => {
            console.log(`  - ${user.nome} (${user.email})`);
        });
        
        // Agora buscar posts de todos os usuários
        const postPromises = usuarios.map(user => buscarPosts(user.id));
        return Promise.all(postPromises);
    })
    .then(todosOsPosts => {
        console.log('📝 Posts de todos os usuários:');
        todosOsPosts.forEach((posts, index) => {
            console.log(`  Usuário ${index + 1}: ${posts.length} posts`);
        });
    })
    .catch(erro => {
        console.error('❌ Erro:', erro.message);
    });

console.log('⏳ Carregando dados em paralelo...');

📊 Métodos de Promise:

Promise.all()

Executa todas em paralelo, falha se uma falhar

Promise.allSettled()

Aguarda todas, independente de falhas

Promise.race()

Retorna a primeira que resolver

Promise.any()

Retorna a primeira que resolver com sucesso


                    

⚡ Async/Await - Sintaxe Moderna

Async/await torna o código assíncrono mais limpo e fácil de ler, como se fosse código síncrono!

📝 Exemplo Prático:

// Simulação de API externa
function simularAPIExterna(endpoint) {
    return new Promise((resolve, reject) => {
        const tempo = Math.random() * 2000 + 500;
        
        setTimeout(() => {
            if (Math.random() > 0.2) { // 80% de sucesso
                const dados = {
                    '/usuarios': [{ id: 1, nome: 'Ana' }, { id: 2, nome: 'João' }],
                    '/posts': [{ id: 1, titulo: 'Post 1' }, { id: 2, titulo: 'Post 2' }],
                    '/comentarios': [{ id: 1, texto: 'Ótimo!' }]
                };
                resolve(dados[endpoint] || { message: 'Dados encontrados' });
            } else {
                reject(new Error(`Erro na API: ${endpoint}`));
            }
        }, tempo);
    });
}

// Função usando async/await
async function carregarDadosCompletos() {
    try {
        console.log('🔄 Iniciando carregamento de dados...');
        
        // Carregamento sequencial
        console.log('👥 Buscando usuários...');
        const usuarios = await simularAPIExterna('/usuarios');
        console.log('✅ Usuários carregados:', usuarios.length, 'encontrados');
        
        console.log('📝 Buscando posts...');
        const posts = await simularAPIExterna('/posts');
        console.log('✅ Posts carregados:', posts.length, 'encontrados');
        
        console.log('💬 Buscando comentários...');
        const comentarios = await simularAPIExterna('/comentarios');
        console.log('✅ Comentários carregados:', comentarios.length, 'encontrados');
        
        // Processamento dos dados
        const resultado = {
            totalUsuarios: usuarios.length,
            totalPosts: posts.length,
            totalComentarios: comentarios.length,
            carregadoEm: new Date().toLocaleTimeString()
        };
        
        console.log('🎯 Carregamento completo!');
        console.log('📊 Resumo:', resultado);
        
        return resultado;
        
    } catch (error) {
        console.error('❌ Erro durante carregamento:', error.message);
        throw error;
    }
}

// Função usando async/await com Promise.all (paralelo)
async function carregarDadosParalelo() {
    try {
        console.log('\n🚀 Carregamento em paralelo...');
        
        const [usuarios, posts, comentarios] = await Promise.all([
            simularAPIExterna('/usuarios'),
            simularAPIExterna('/posts'),
            simularAPIExterna('/comentarios')
        ]);
        
        console.log('⚡ Todos os dados carregados simultaneamente!');
        console.log('📊 Resultado:', {
            usuarios: usuarios.length,
            posts: posts.length,
            comentarios: comentarios.length
        });
        
    } catch (error) {
        console.error('❌ Erro no carregamento paralelo:', error.message);
    }
}

// Executando os exemplos
console.log('=== DEMONSTRAÇÃO ASYNC/AWAIT ===');
carregarDadosCompletos();

setTimeout(() => {
    carregarDadosParalelo();
}, 3000);

🔄 Sequencial vs Paralelo:

⏱️ Comparação de Performance:
Sequencial: ~4-6 segundos
Paralelo: ~1-2 segundos
💡 Quando usar cada um:
  • Sequencial: Quando uma operação depende da anterior
  • Paralelo: Quando operações são independentes
  • Try/catch: Sempre para tratar erros
  • Async/await: Código mais limpo que .then()

                    

🎯 Exercício Prático 1: Sistema de Download

Crie um sistema que simula downloads de arquivos usando async/await e Promise.all()!

📋 Requisitos:

  • Função que simula download de arquivo (com Promise)
  • Função async que baixa múltiplos arquivos em paralelo
  • Tratamento de erros com try/catch
  • Exibir progresso e tempo total de download

💻 Seu Código:

📊 Resultado:

Execute seu código para ver o resultado...
📊 Score: 0/100
✅ Testes: 0/4
🎯 Status: Pendente
3

Nível Avançado

Introdução ao Express.js - Framework Web

🚀 Express.js - Seu Primeiro Framework

Express.js é o framework web mais popular para Node.js. Ele simplifica a criação de servidores e APIs!

📝 Exemplo Prático:

// Simulação do Express.js
// (Em Node.js real: const express = require('express'))

// 1. Simulando o Express
function criarExpress() {
    const rotas = [];
    const middlewares = [];
    
    const app = {
        // Método GET
        get: (caminho, handler) => {
            rotas.push({ metodo: 'GET', caminho, handler });
            console.log(`📍 Rota GET ${caminho} registrada`);
        },
        
        // Método POST
        post: (caminho, handler) => {
            rotas.push({ metodo: 'POST', caminho, handler });
            console.log(`📍 Rota POST ${caminho} registrada`);
        },
        
        // Middleware
        use: (middleware) => {
            middlewares.push(middleware);
            console.log(`🔧 Middleware registrado`);
        },
        
        // Iniciar servidor
        listen: (porta, callback) => {
            console.log(`🚀 Servidor Express rodando na porta ${porta}`);
            if (callback) callback();
            return {
                rotas,
                middlewares,
                porta
            };
        },
        
        // Simular requisição
        simularRequisicao: (metodo, caminho, dados = {}) => {
            console.log(`\n📥 ${metodo} ${caminho}`);
            
            // Executar middlewares
            middlewares.forEach(middleware => {
                console.log('🔧 Executando middleware...');
                middleware({ metodo, caminho, dados }, { status: 200 }, () => {});
            });
            
            // Encontrar rota
            const rota = rotas.find(r => r.metodo === metodo && r.caminho === caminho);
            
            if (rota) {
                const req = { metodo, caminho, dados, params: {}, query: {} };
                const res = {
                    status: (code) => {
                        console.log(`📤 Status: ${code}`);
                        return res;
                    },
                    json: (data) => {
                        console.log('📄 Resposta JSON:', JSON.stringify(data, null, 2));
                        return res;
                    },
                    send: (data) => {
                        console.log('📄 Resposta:', data);
                        return res;
                    }
                };
                
                rota.handler(req, res);
            } else {
                console.log('❌ 404 - Rota não encontrada');
            }
        }
    };
    
    return app;
}

// 2. Criando aplicação Express
console.log('=== DEMONSTRAÇÃO DO EXPRESS.JS ===');

const express = criarExpress;
const app = express();

// 3. Middleware de log
app.use((req, res, next) => {
    const timestamp = new Date().toLocaleTimeString();
    console.log(`[${timestamp}] ${req.metodo} ${req.caminho}`);
    next();
});

// 4. Rotas básicas
app.get('/', (req, res) => {
    res.status(200).send('Bem-vindo ao Express!');
});

app.get('/usuarios', (req, res) => {
    const usuarios = [
        { id: 1, nome: 'Ana', email: 'ana@email.com' },
        { id: 2, nome: 'João', email: 'joao@email.com' }
    ];
    res.status(200).json(usuarios);
});

app.post('/usuarios', (req, res) => {
    const novoUsuario = {
        id: Date.now(),
        nome: req.dados.nome || 'Usuário',
        email: req.dados.email || 'email@exemplo.com'
    };
    res.status(201).json({ 
        mensagem: 'Usuário criado com sucesso!', 
        usuario: novoUsuario 
    });
});

app.get('/sobre', (req, res) => {
    res.status(200).json({
        aplicacao: 'Minha API Express',
        versao: '1.0.0',
        autor: 'Desenvolvedor Backend'
    });
});

// 5. Iniciar servidor
const servidor = app.listen(3000, () => {
    console.log('✅ Servidor Express iniciado com sucesso!');
});

// 6. Simular algumas requisições
console.log('\n🧪 Testando rotas:');
setTimeout(() => {
    app.simularRequisicao('GET', '/');
    app.simularRequisicao('GET', '/usuarios');
    app.simularRequisicao('POST', '/usuarios', { nome: 'Maria', email: 'maria@email.com' });
    app.simularRequisicao('GET', '/sobre');
    app.simularRequisicao('GET', '/inexistente');
}, 1000);

🔧 Conceitos do Express:

Rotas

app.get(), app.post(), app.put(), app.delete()

Middleware

Funções que executam entre req e res

Request (req)

Dados da requisição (params, query, body)

Response (res)

Enviar resposta (json, send, status)

💡 Vantagens do Express:
  • ✅ Sintaxe simples e intuitiva
  • ✅ Sistema de middleware poderoso
  • ✅ Roteamento flexível
  • ✅ Grande ecossistema de plugins
  • ✅ Performance otimizada

                    

🎯 Exercício Prático 3: API de Biblioteca

Crie uma API completa para gerenciar livros usando Express.js com todas as operações CRUD!

📋 Requisitos:

  • Criar aplicação Express com middleware de log
  • Rota GET /livros - listar todos os livros
  • Rota POST /livros - adicionar novo livro
  • Rota GET /livros/:id - buscar livro por ID
  • Simular requisições para testar a API

💻 Seu Código:

📊 Resultado:

Execute seu código para ver o resultado...
📊 Score: 0/100
✅ Testes: 0/4
🎯 Status: Pendente
💻

Console Interativo

Teste todos os conceitos aprendidos em tempo real!

📝 Editor de Código

📺 Saída do Console

Console JavaScript - Semana 2 Backend
Digite código no editor e clique em "Executar" para ver o resultado...
>

📊 Estatísticas:

🚀 Execuções: 0
⏱️ Última execução: -
📝 Linhas de código: 0
❌ Erros: 0

🎯 Desafios Rápidos

🎉 Parabéns! Você concluiu a Semana 2

JavaScript Assíncrono

Dominou Promises, async/await e Promise.all()

📁

Módulos Node.js

Aprendeu fs, path e manipulação de arquivos

🚀

Express.js

Criou seu primeiro servidor web com framework

🚀 Próxima semana: APIs REST, Middleware e Estrutura de Projetos!

2

Nível Intermediário

Módulos Nativos do Node.js: fs, path, http, url

📁 Módulo File System (fs)

O módulo fs permite ler, escrever e manipular arquivos no sistema. Essencial para qualquer aplicação backend!

📝 Exemplo Prático:

// Simulação do módulo fs do Node.js
// (Em Node.js real: const fs = require('fs').promises)

// 1. Simulando operações de arquivo
const fs = {
    // Leitura de arquivo
    readFile: (caminho) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                const arquivos = {
                    'config.json': JSON.stringify({
                        nome: 'Minha App',
                        versao: '1.0.0',
                        porta: 3000
                    }, null, 2),
                    'usuarios.txt': 'Ana\nJoão\nMaria\nPedro',
                    'log.txt': '2024-01-15 10:30 - Servidor iniciado\n2024-01-15 10:31 - Usuário logado'
                };
                
                if (arquivos[caminho]) {
                    resolve(arquivos[caminho]);
                } else {
                    reject(new Error(`Arquivo não encontrado: ${caminho}`));
                }
            }, 500);
        });
    },
    
    // Escrita de arquivo
    writeFile: (caminho, conteudo) => {
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log(`✅ Arquivo '${caminho}' salvo com sucesso!`);
                console.log(`📄 Conteúdo: ${conteudo.substring(0, 50)}...`);
                resolve();
            }, 300);
        });
    },
    
    // Verificar se arquivo existe
    access: (caminho) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                const arquivosExistentes = ['config.json', 'usuarios.txt', 'log.txt'];
                if (arquivosExistentes.includes(caminho)) {
                    resolve();
                } else {
                    reject(new Error('Arquivo não existe'));
                }
            }, 200);
        });
    }
};

// Função para demonstrar operações com arquivos
async function gerenciarArquivos() {
    try {
        console.log('=== DEMONSTRAÇÃO DO MÓDULO FS ===');
        
        // 1. Verificar se arquivo existe
        console.log('🔍 Verificando se config.json existe...');
        await fs.access('config.json');
        console.log('✅ Arquivo existe!');
        
        // 2. Ler arquivo de configuração
        console.log('📖 Lendo arquivo de configuração...');
        const configData = await fs.readFile('config.json');
        const config = JSON.parse(configData);
        console.log('⚙️ Configuração carregada:', config);
        
        // 3. Ler lista de usuários
        console.log('👥 Lendo lista de usuários...');
        const usuariosData = await fs.readFile('usuarios.txt');
        const usuarios = usuariosData.split('\n');
        console.log(`📋 ${usuarios.length} usuários encontrados:`, usuarios);
        
        // 4. Criar novo arquivo de relatório
        const relatorio = {
            dataGeracao: new Date().toISOString(),
            totalUsuarios: usuarios.length,
            configuracao: config,
            status: 'ativo'
        };
        
        console.log('📝 Criando relatório...');
        await fs.writeFile('relatorio.json', JSON.stringify(relatorio, null, 2));
        
        console.log('🎯 Operações de arquivo concluídas!');
        
    } catch (error) {
        console.error('❌ Erro:', error.message);
    }
}

// Executar demonstração
gerenciarArquivos();

📊 Métodos Principais:

fs.readFile()

Lê conteúdo de um arquivo

fs.writeFile()

Escreve conteúdo em um arquivo

fs.access()

Verifica se arquivo/pasta existe

fs.mkdir()

Cria diretórios


                    

🛣️ Módulo Path

O módulo path ajuda a trabalhar com caminhos de arquivos de forma segura, independente do sistema operacional!

📝 Exemplo Prático:

// Simulação do módulo path do Node.js
// (Em Node.js real: const path = require('path'))

const path = {
    // Junta caminhos de forma segura
    join: (...caminhos) => {
        return caminhos.join('/').replace(/\/+/g, '/');
    },
    
    // Resolve caminho absoluto
    resolve: (...caminhos) => {
        const base = '/home/usuario/projeto';
        return path.join(base, ...caminhos);
    },
    
    // Extrai nome do arquivo
    basename: (caminho, ext) => {
        const nome = caminho.split('/').pop();
        if (ext && nome.endsWith(ext)) {
            return nome.slice(0, -ext.length);
        }
        return nome;
    },
    
    // Extrai diretório
    dirname: (caminho) => {
        const partes = caminho.split('/');
        partes.pop();
        return partes.join('/') || '/';
    },
    
    // Extrai extensão
    extname: (caminho) => {
        const nome = path.basename(caminho);
        const pontoIndex = nome.lastIndexOf('.');
        return pontoIndex > 0 ? nome.slice(pontoIndex) : '';
    }
};

function demonstrarPath() {
    console.log('=== DEMONSTRAÇÃO DO MÓDULO PATH ===');
    
    // Exemplos de caminhos
    const caminhos = [
        'src/controllers/userController.js',
        'public/images/logo.png',
        'config/database.json',
        'uploads/documents/relatorio.pdf'
    ];
    
    caminhos.forEach(caminho => {
        console.log(`\n📁 Analisando: ${caminho}`);
        console.log(`  📂 Diretório: ${path.dirname(caminho)}`);
        console.log(`  📄 Nome: ${path.basename(caminho)}`);
        console.log(`  🏷️ Extensão: ${path.extname(caminho)}`);
        console.log(`  📍 Caminho absoluto: ${path.resolve(caminho)}`);
    });
    
    // Construindo caminhos seguros
    console.log('\n🔧 Construindo caminhos:');
    const caminhoConfig = path.join('config', 'app.json');
    const caminhoUpload = path.join('uploads', 'user-123', 'avatar.jpg');
    const caminhoLog = path.join('logs', '2024', '01', 'app.log');
    
    console.log(`  ⚙️ Config: ${caminhoConfig}`);
    console.log(`  📤 Upload: ${caminhoUpload}`);
    console.log(`  📋 Log: ${caminhoLog}`);
    
    // Casos práticos
    console.log('\n💼 Casos práticos:');
    
    // Validar extensões de arquivo
    const arquivosUpload = ['foto.jpg', 'documento.pdf', 'virus.exe', 'musica.mp3'];
    const extensoesPermitidas = ['.jpg', '.png', '.pdf', '.mp3'];
    
    arquivosUpload.forEach(arquivo => {
        const ext = path.extname(arquivo);
        const permitido = extensoesPermitidas.includes(ext);
        console.log(`  ${permitido ? '✅' : '❌'} ${arquivo} (${ext})`);
    });
    
    console.log('\n🎯 Demonstração do path concluída!');
}

// Executar demonstração
demonstrарPath();

🔧 Métodos Úteis:

path.join(): Une caminhos
path.resolve(): Caminho absoluto
path.basename(): Nome do arquivo
path.dirname(): Diretório pai
path.extname(): Extensão
💡 Dicas importantes:
  • ✅ Sempre use path.join() para unir caminhos
  • ✅ path.resolve() para caminhos absolutos
  • ✅ Funciona em Windows, Mac e Linux
  • ✅ Evita problemas com barras / e \

                    

🎯 Exercício Prático 2: Gerenciador de Logs

Crie um sistema de logs que organiza arquivos por data usando os módulos fs e path!

📋 Requisitos:

  • Função para criar estrutura de pastas de logs (ano/mês)
  • Função para escrever log com timestamp
  • Função para ler logs de uma data específica
  • Usar path.join() para caminhos seguros

💻 Seu Código:

📊 Resultado:

Execute seu código para ver o resultado...
📊 Score: 0/100
✅ Testes: 0/4
🎯 Status: Pendente