Tools: Chrome DevTools: La guía de debugging que todo principiante necesita (adiós console.log) (2026)
¿Qué vamos a aprender?
El problema: console.log everywhere
Proyecto: Bug Hunter Dashboard
Paso 1: Abrir Chrome DevTools
Panel Console: tu mejor amigo
Bug #1: Calculadora que concatena
Bug #2: Elemento que no existe
Bug #3: API call fallida
Panel Elements: DOM en vivo
Performance: encontrar código lento
Breakpoints condicionales
Memory leaks
Debugging responsive design
Security: detectar XSS en DevTools
Shortcuts que te harán más rápido
Ejercicios adicionales para practicar
Siguientes pasos ¿Llevas meses llenando tu código de console.log() cada vez que algo no funciona? Es hora de debuggear como un profesional. En este tutorial vas a aprender a usar Chrome DevTools para encontrar y arreglar bugs de forma eficiente. No más adivinar qué está mal: vas a ver exactamente qué está pasando en tu código. Seamos honestos. Todos hemos estado aquí: Problemas con este approach: Vamos a crear una aplicación con errores intencionados que iremos solucionando usando Chrome DevTools. Objetivo: usar Chrome DevTools para encontrar y arreglar estos 3 bugs sin modificar el código a ciegas. Los paneles más importantes: 💡 Tip pro: en la Console puedes ejecutar cualquier JavaScript. Es como tener un playground para probar código al instante. Si introduces 5 + 3, obtienes "53" en lugar de 8. ¿Por qué? ❌ Método tradicional (malo): ✅ Método profesional — Breakpoints: Cuando el código se pausa puedes: 🎯 Descubrimiento: num1 y num2 son strings ("5" y "3"), no números. Por eso "5" + "3" = "53". Intenta agregar una tarea — no funciona. Abre la Console y verás: Eso significa que taskList es null. Investiga directamente en la Console: 💡 Cuando algo devuelve null, casi siempre es un selector incorrecto. La Console es perfecta para probarlos al instante. Para este bug usamos el panel Network: El panel Network te muestra: 🎯 Descubrimiento: la URL tiene un typo: /userss en lugar de /users. El panel Elements te permite inspeccionar y modificar HTML/CSS en tiempo real: Cómo usar el panel Performance: Si ves errores CSP en la Console, significa que hay restricciones de seguridad activas en la página. Ahora que dominas Chrome DevTools, nunca más tendrás que llenar tu código de console.log innecesarios. Has aprendido a: El debugging es una skill que se mejora con la práctica. Úsalo en todos tus proyectos, incluso los pequeños. Con el tiempo se convierte en tu segunda naturaleza. Si este tutorial te ha sido útil, en StudyCode Pro encontrarás más guías prácticas de JavaScript, CSS y desarrollo web — sin teoría aburrida. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
// ❌ El debugging "a lo bestia"
function calculateTotal(items) { console.log('items:', items); let total = 0; console.log('total inicial:', total); for (let item of items) { console.log('item actual:', item); total += item.price; console.log('total después de sumar:', total); } console.log('total final:', total); return total;
}
// ❌ El debugging "a lo bestia"
function calculateTotal(items) { console.log('items:', items); let total = 0; console.log('total inicial:', total); for (let item of items) { console.log('item actual:', item); total += item.price; console.log('total después de sumar:', total); } console.log('total final:', total); return total;
}
// ❌ El debugging "a lo bestia"
function calculateTotal(items) { console.log('items:', items); let total = 0; console.log('total inicial:', total); for (let item of items) { console.log('item actual:', item); total += item.price; console.log('total después de sumar:', total); } console.log('total final:', total); return total;
}
<!-- index.html -->
<!DOCTYPE html>
<html lang="es">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Bug Hunter Dashboard</title> <link rel="stylesheet" href="style.css">
</head>
<body> <header> <h1>Bug Hunter Dashboard</h1> <p>Encuentra y arregla los bugs usando Chrome DevTools</p> </header> <main> <section id="calculator"> <h2>🧮 Calculadora (tiene bugs)</h2> <div class="calculator-container"> <input type="number" id="num1" placeholder="Número 1"> <input type="number" id="num2" placeholder="Número 2"> <button onclick="calculate()">Sumar</button> <div id="result">Resultado: -</div> </div> </section> <section id="todo-list"> <h2>📝 Lista de Tareas (también tiene bugs)</h2> <div class="todo-container"> <input type="text" id="todo-input" placeholder="Nueva tarea..."> <button onclick="addTask()">Agregar</button> <ul id="task-list"></ul> </div> </section> <section id="api-section"> <h2>🌐 API Caller (fallos de red)</h2> <button onclick="fetchUserData()">Cargar Usuarios</button> <div id="loading" style="display: none;">Cargando...</div> <div id="user-data"></div> </section> </main> <script src="script.js"></script>
</body>
</html>
<!-- index.html -->
<!DOCTYPE html>
<html lang="es">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Bug Hunter Dashboard</title> <link rel="stylesheet" href="style.css">
</head>
<body> <header> <h1>Bug Hunter Dashboard</h1> <p>Encuentra y arregla los bugs usando Chrome DevTools</p> </header> <main> <section id="calculator"> <h2>🧮 Calculadora (tiene bugs)</h2> <div class="calculator-container"> <input type="number" id="num1" placeholder="Número 1"> <input type="number" id="num2" placeholder="Número 2"> <button onclick="calculate()">Sumar</button> <div id="result">Resultado: -</div> </div> </section> <section id="todo-list"> <h2>📝 Lista de Tareas (también tiene bugs)</h2> <div class="todo-container"> <input type="text" id="todo-input" placeholder="Nueva tarea..."> <button onclick="addTask()">Agregar</button> <ul id="task-list"></ul> </div> </section> <section id="api-section"> <h2>🌐 API Caller (fallos de red)</h2> <button onclick="fetchUserData()">Cargar Usuarios</button> <div id="loading" style="display: none;">Cargando...</div> <div id="user-data"></div> </section> </main> <script src="script.js"></script>
</body>
</html>
<!-- index.html -->
<!DOCTYPE html>
<html lang="es">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Bug Hunter Dashboard</title> <link rel="stylesheet" href="style.css">
</head>
<body> <header> <h1>Bug Hunter Dashboard</h1> <p>Encuentra y arregla los bugs usando Chrome DevTools</p> </header> <main> <section id="calculator"> <h2>🧮 Calculadora (tiene bugs)</h2> <div class="calculator-container"> <input type="number" id="num1" placeholder="Número 1"> <input type="number" id="num2" placeholder="Número 2"> <button onclick="calculate()">Sumar</button> <div id="result">Resultado: -</div> </div> </section> <section id="todo-list"> <h2>📝 Lista de Tareas (también tiene bugs)</h2> <div class="todo-container"> <input type="text" id="todo-input" placeholder="Nueva tarea..."> <button onclick="addTask()">Agregar</button> <ul id="task-list"></ul> </div> </section> <section id="api-section"> <h2>🌐 API Caller (fallos de red)</h2> <button onclick="fetchUserData()">Cargar Usuarios</button> <div id="loading" style="display: none;">Cargando...</div> <div id="user-data"></div> </section> </main> <script src="script.js"></script>
</body>
</html>
// script.js - JavaScript con bugs intencionados // Bug #1: Calculadora suma strings en lugar de números
function calculate() { const num1 = document.getElementById('num1').value; const num2 = document.getElementById('num2').value; const result = num1 + num2; // ❌ Suma strings! document.getElementById('result').textContent = 'Resultado: ' + result;
} // Bug #2: Error en querySelector
function addTask() { const input = document.getElementById('todo-input'); const taskList = document.querySelector('#task-lists'); // ❌ ID incorrecto! if (input.value.trim()) { const li = document.createElement('li'); li.textContent = input.value; taskList.appendChild(li); // ❌ Falla porque taskList es null input.value = ''; }
} // Bug #3: API call con URL incorrecta
async function fetchUserData() { const loading = document.getElementById('loading'); const userData = document.getElementById('user-data'); loading.style.display = 'block'; try { const response = await fetch('https://jsonplaceholder.typicode.com/userss'); // ❌ Typo const users = await response.json(); userData.innerHTML = users.map(user => `<p>${user.name}</p>`).join(''); } catch (error) { userData.innerHTML = 'Error cargando datos'; // ❌ Error handling insuficiente } finally { loading.style.display = 'none'; }
}
// script.js - JavaScript con bugs intencionados // Bug #1: Calculadora suma strings en lugar de números
function calculate() { const num1 = document.getElementById('num1').value; const num2 = document.getElementById('num2').value; const result = num1 + num2; // ❌ Suma strings! document.getElementById('result').textContent = 'Resultado: ' + result;
} // Bug #2: Error en querySelector
function addTask() { const input = document.getElementById('todo-input'); const taskList = document.querySelector('#task-lists'); // ❌ ID incorrecto! if (input.value.trim()) { const li = document.createElement('li'); li.textContent = input.value; taskList.appendChild(li); // ❌ Falla porque taskList es null input.value = ''; }
} // Bug #3: API call con URL incorrecta
async function fetchUserData() { const loading = document.getElementById('loading'); const userData = document.getElementById('user-data'); loading.style.display = 'block'; try { const response = await fetch('https://jsonplaceholder.typicode.com/userss'); // ❌ Typo const users = await response.json(); userData.innerHTML = users.map(user => `<p>${user.name}</p>`).join(''); } catch (error) { userData.innerHTML = 'Error cargando datos'; // ❌ Error handling insuficiente } finally { loading.style.display = 'none'; }
}
// script.js - JavaScript con bugs intencionados // Bug #1: Calculadora suma strings en lugar de números
function calculate() { const num1 = document.getElementById('num1').value; const num2 = document.getElementById('num2').value; const result = num1 + num2; // ❌ Suma strings! document.getElementById('result').textContent = 'Resultado: ' + result;
} // Bug #2: Error en querySelector
function addTask() { const input = document.getElementById('todo-input'); const taskList = document.querySelector('#task-lists'); // ❌ ID incorrecto! if (input.value.trim()) { const li = document.createElement('li'); li.textContent = input.value; taskList.appendChild(li); // ❌ Falla porque taskList es null input.value = ''; }
} // Bug #3: API call con URL incorrecta
async function fetchUserData() { const loading = document.getElementById('loading'); const userData = document.getElementById('user-data'); loading.style.display = 'block'; try { const response = await fetch('https://jsonplaceholder.typicode.com/userss'); // ❌ Typo const users = await response.json(); userData.innerHTML = users.map(user => `<p>${user.name}</p>`).join(''); } catch (error) { userData.innerHTML = 'Error cargando datos'; // ❌ Error handling insuficiente } finally { loading.style.display = 'none'; }
}
/* style.css */
* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px;
}
header { text-align: center; margin-bottom: 40px; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px;
}
section { margin-bottom: 30px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background: #f9f9f9;
}
input, button { padding: 10px; margin: 5px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px;
}
button { background: #007bff; color: white; cursor: pointer; transition: background 0.3s;
}
button:hover { background: #0056b3; }
#result { margin-top: 10px; font-weight: bold; padding: 10px; background: #e9ecef; border-radius: 4px;
}
#task-list li { list-style: none; padding: 8px; background: white; margin: 5px 0; border-radius: 4px; border-left: 4px solid #28a745;
}
/* style.css */
* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px;
}
header { text-align: center; margin-bottom: 40px; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px;
}
section { margin-bottom: 30px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background: #f9f9f9;
}
input, button { padding: 10px; margin: 5px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px;
}
button { background: #007bff; color: white; cursor: pointer; transition: background 0.3s;
}
button:hover { background: #0056b3; }
#result { margin-top: 10px; font-weight: bold; padding: 10px; background: #e9ecef; border-radius: 4px;
}
#task-list li { list-style: none; padding: 8px; background: white; margin: 5px 0; border-radius: 4px; border-left: 4px solid #28a745;
}
/* style.css */
* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px;
}
header { text-align: center; margin-bottom: 40px; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px;
}
section { margin-bottom: 30px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background: #f9f9f9;
}
input, button { padding: 10px; margin: 5px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px;
}
button { background: #007bff; color: white; cursor: pointer; transition: background 0.3s;
}
button:hover { background: #0056b3; }
#result { margin-top: 10px; font-weight: bold; padding: 10px; background: #e9ecef; border-radius: 4px;
}
#task-list li { list-style: none; padding: 8px; background: white; margin: 5px 0; border-radius: 4px; border-left: 4px solid #28a745;
}
// Inspeccionar elementos directamente
$('#num1') // Equivale a document.querySelector
$$('button') // Equivale a document.querySelectorAll // Logs más informativos
console.table(datos) // Muestra arrays/objetos como tabla
console.group('Cálculos') // Agrupa logs
console.error('Error!') // Log con estilo de error
console.warn('Cuidado!') // Log con estilo de warning // Medir performance
console.time('operacion');
// ... código a medir ...
console.timeEnd('operacion');
// Inspeccionar elementos directamente
$('#num1') // Equivale a document.querySelector
$$('button') // Equivale a document.querySelectorAll // Logs más informativos
console.table(datos) // Muestra arrays/objetos como tabla
console.group('Cálculos') // Agrupa logs
console.error('Error!') // Log con estilo de error
console.warn('Cuidado!') // Log con estilo de warning // Medir performance
console.time('operacion');
// ... código a medir ...
console.timeEnd('operacion');
// Inspeccionar elementos directamente
$('#num1') // Equivale a document.querySelector
$$('button') // Equivale a document.querySelectorAll // Logs más informativos
console.table(datos) // Muestra arrays/objetos como tabla
console.group('Cálculos') // Agrupa logs
console.error('Error!') // Log con estilo de error
console.warn('Cuidado!') // Log con estilo de warning // Medir performance
console.time('operacion');
// ... código a medir ...
console.timeEnd('operacion');
function calculate() { const num1 = document.getElementById('num1').value; console.log('num1:', num1, typeof num1); // Modificando el código
}
function calculate() { const num1 = document.getElementById('num1').value; console.log('num1:', num1, typeof num1); // Modificando el código
}
function calculate() { const num1 = document.getElementById('num1').value; console.log('num1:', num1, typeof num1); // Modificando el código
}
// ✅ La solución
function calculate() { const num1 = parseFloat(document.getElementById('num1').value); const num2 = parseFloat(document.getElementById('num2').value); const result = num1 + num2; document.getElementById('result').textContent = 'Resultado: ' + result;
}
// ✅ La solución
function calculate() { const num1 = parseFloat(document.getElementById('num1').value); const num2 = parseFloat(document.getElementById('num2').value); const result = num1 + num2; document.getElementById('result').textContent = 'Resultado: ' + result;
}
// ✅ La solución
function calculate() { const num1 = parseFloat(document.getElementById('num1').value); const num2 = parseFloat(document.getElementById('num2').value); const result = num1 + num2; document.getElementById('result').textContent = 'Resultado: ' + result;
}
Cannot read property 'appendChild' of null
Cannot read property 'appendChild' of null
Cannot read property 'appendChild' of null
document.querySelector('#task-lists') // null — no existe!
document.querySelector('#task-list') // <ul id="task-list"></ul> — ¡aquí está! // El problema: typo en el ID
// ❌ Código busca: '#task-lists' (con S)
// ✅ HTML tiene: '#task-list' (sin S)
document.querySelector('#task-lists') // null — no existe!
document.querySelector('#task-list') // <ul id="task-list"></ul> — ¡aquí está! // El problema: typo en el ID
// ❌ Código busca: '#task-lists' (con S)
// ✅ HTML tiene: '#task-list' (sin S)
document.querySelector('#task-lists') // null — no existe!
document.querySelector('#task-list') // <ul id="task-list"></ul> — ¡aquí está! // El problema: typo en el ID
// ❌ Código busca: '#task-lists' (con S)
// ✅ HTML tiene: '#task-list' (sin S)
// ✅ La solución
function addTask() { const input = document.getElementById('todo-input'); const taskList = document.querySelector('#task-list'); // ← correcto if (input.value.trim()) { const li = document.createElement('li'); li.textContent = input.value; taskList.appendChild(li); input.value = ''; }
}
// ✅ La solución
function addTask() { const input = document.getElementById('todo-input'); const taskList = document.querySelector('#task-list'); // ← correcto if (input.value.trim()) { const li = document.createElement('li'); li.textContent = input.value; taskList.appendChild(li); input.value = ''; }
}
// ✅ La solución
function addTask() { const input = document.getElementById('todo-input'); const taskList = document.querySelector('#task-list'); // ← correcto if (input.value.trim()) { const li = document.createElement('li'); li.textContent = input.value; taskList.appendChild(li); input.value = ''; }
}
// ✅ La solución
const response = await fetch('https://jsonplaceholder.typicode.com/users');
// ✅ La solución
const response = await fetch('https://jsonplaceholder.typicode.com/users');
// ✅ La solución
const response = await fetch('https://jsonplaceholder.typicode.com/users');
/* Prueba cambiar estos estilos desde el panel Elements: */
header { background: #ff6b6b;
}
button { padding: 15px 30px; font-size: 18px;
}
/* Prueba cambiar estos estilos desde el panel Elements: */
header { background: #ff6b6b;
}
button { padding: 15px 30px; font-size: 18px;
}
/* Prueba cambiar estos estilos desde el panel Elements: */
header { background: #ff6b6b;
}
button { padding: 15px 30px; font-size: 18px;
}
// Función intencionalmente lenta
function slowFunction() { let result = 0; for (let i = 0; i < 1000000; i++) { result += Math.random(); } return result;
} console.time('Función lenta');
slowFunction();
console.timeEnd('Función lenta');
// Función intencionalmente lenta
function slowFunction() { let result = 0; for (let i = 0; i < 1000000; i++) { result += Math.random(); } return result;
} console.time('Función lenta');
slowFunction();
console.timeEnd('Función lenta');
// Función intencionalmente lenta
function slowFunction() { let result = 0; for (let i = 0; i < 1000000; i++) { result += Math.random(); } return result;
} console.time('Función lenta');
slowFunction();
console.timeEnd('Función lenta');
function processItems(items) { for (let i = 0; i < items.length; i++) { const item = items[i]; // ⭐ Pon aquí un breakpoint condicional: i === 5 console.log('Procesando item:', item); }
} processItems(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
function processItems(items) { for (let i = 0; i < items.length; i++) { const item = items[i]; // ⭐ Pon aquí un breakpoint condicional: i === 5 console.log('Procesando item:', item); }
} processItems(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
function processItems(items) { for (let i = 0; i < items.length; i++) { const item = items[i]; // ⭐ Pon aquí un breakpoint condicional: i === 5 console.log('Procesando item:', item); }
} processItems(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
// ❌ Memory leak — listener que nunca se limpia
function createMemoryLeak() { const element = document.createElement('div'); const data = new Array(1000000).fill('memory'); element.addEventListener('click', function() { console.log(data.length); // Mantiene referencia a 'data' });
} // ✅ Versión correcta con cleanup
function createProperCleanup() { const element = document.createElement('div'); const controller = new AbortController(); element.addEventListener('click', function() { console.log('click'); }, { signal: controller.signal }); controller.abort(); // Elimina todos los listeners
}
// ❌ Memory leak — listener que nunca se limpia
function createMemoryLeak() { const element = document.createElement('div'); const data = new Array(1000000).fill('memory'); element.addEventListener('click', function() { console.log(data.length); // Mantiene referencia a 'data' });
} // ✅ Versión correcta con cleanup
function createProperCleanup() { const element = document.createElement('div'); const controller = new AbortController(); element.addEventListener('click', function() { console.log('click'); }, { signal: controller.signal }); controller.abort(); // Elimina todos los listeners
}
// ❌ Memory leak — listener que nunca se limpia
function createMemoryLeak() { const element = document.createElement('div'); const data = new Array(1000000).fill('memory'); element.addEventListener('click', function() { console.log(data.length); // Mantiene referencia a 'data' });
} // ✅ Versión correcta con cleanup
function createProperCleanup() { const element = document.createElement('div'); const controller = new AbortController(); element.addEventListener('click', function() { console.log('click'); }, { signal: controller.signal }); controller.abort(); // Elimina todos los listeners
}
// ❌ NUNCA hagas esto — XSS vulnerability
function unsafeCode(userInput) { document.getElementById('output').innerHTML = userInput;
} // ✅ Versión segura
function safeCode(userInput) { document.getElementById('output').textContent = userInput;
}
// ❌ NUNCA hagas esto — XSS vulnerability
function unsafeCode(userInput) { document.getElementById('output').innerHTML = userInput;
} // ✅ Versión segura
function safeCode(userInput) { document.getElementById('output').textContent = userInput;
}
// ❌ NUNCA hagas esto — XSS vulnerability
function unsafeCode(userInput) { document.getElementById('output').innerHTML = userInput;
} // ✅ Versión segura
function safeCode(userInput) { document.getElementById('output').textContent = userInput;
}
// Atajos útiles dentro de la Console
clear() // Limpiar console (o Ctrl+L)
$_ // Última expresión evaluada
$0 // Último elemento inspeccionado
$1 // Penúltimo elemento inspeccionado dir(window) // Lista todas las propiedades de window
keys(localStorage) // Claves del localStorage
values(localStorage) // Valores del localStorage
// Atajos útiles dentro de la Console
clear() // Limpiar console (o Ctrl+L)
$_ // Última expresión evaluada
$0 // Último elemento inspeccionado
$1 // Penúltimo elemento inspeccionado dir(window) // Lista todas las propiedades de window
keys(localStorage) // Claves del localStorage
values(localStorage) // Valores del localStorage
// Atajos útiles dentro de la Console
clear() // Limpiar console (o Ctrl+L)
$_ // Última expresión evaluada
$0 // Último elemento inspeccionado
$1 // Penúltimo elemento inspeccionado dir(window) // Lista todas las propiedades de window
keys(localStorage) // Claves del localStorage
values(localStorage) // Valores del localStorage
// Bug #4: Array manipulation error
function removeItem(arr, index) { // ❌ Modifica el array original return arr.splice(index, 1);
} // Bug #5: Async/await sin error handling
async function loadData() { // ❌ Si la API falla, la app crashea const response = await fetch('/api/data'); const data = await response.json(); return data;
} // Bug #6: Event listener leak
function setupButton() { const button = document.querySelector('#my-button'); // ❌ Añade listener cada vez que se llama la función button.addEventListener('click', handleClick);
}
// Bug #4: Array manipulation error
function removeItem(arr, index) { // ❌ Modifica el array original return arr.splice(index, 1);
} // Bug #5: Async/await sin error handling
async function loadData() { // ❌ Si la API falla, la app crashea const response = await fetch('/api/data'); const data = await response.json(); return data;
} // Bug #6: Event listener leak
function setupButton() { const button = document.querySelector('#my-button'); // ❌ Añade listener cada vez que se llama la función button.addEventListener('click', handleClick);
}
// Bug #4: Array manipulation error
function removeItem(arr, index) { // ❌ Modifica el array original return arr.splice(index, 1);
} // Bug #5: Async/await sin error handling
async function loadData() { // ❌ Si la API falla, la app crashea const response = await fetch('/api/data'); const data = await response.json(); return data;
} // Bug #6: Event listener leak
function setupButton() { const button = document.querySelector('#my-button'); // ❌ Añade listener cada vez que se llama la función button.addEventListener('click', handleClick);
} - Dominar Chrome DevTools desde cero
- Usar breakpoints en lugar de console.log
- Inspeccionar y modificar DOM en tiempo real
- Analizar peticiones de red y errores de API
- Detectar problemas de rendimiento
- Debuggear paso a paso con el Sources panel - JavaScript básico: variables, funciones, DOM
- HTML/CSS: selectores, estructura básica
- Google Chrome actualizado - Tienes que modificar tu código solo para debuggear
- Llenas tu código de ruido innecesario
- No puedes ver el estado completo de la aplicación
- Tienes que recordar quitar todos los console.log - Abre el panel Sources
- Encuentra script.js en el file navigator
- Haz clic en el número de línea donde está const num1 = ...
- Aparece un punto azul — ¡has puesto un breakpoint!
- Recarga la página y prueba la calculadora
- El código se pausa exactamente en esa línea - Inspeccionar variables: pasa el mouse sobre num1 o num2
- Usar la Console: escribe typeof num1 y presiona Enter
- Ver el Scope: panel derecho → variables locales - Abre el panel Network
- Haz clic en "Cargar Usuarios"
- Verás una petición en rojo — significa que falló
- Haz clic en la petición fallida
- Pestaña Response → verás el error 404
- Pestaña Headers → verás la URL incorrecta - Status: 200 = OK, 404 = No encontrado
- Time: cuánto tardó la petición
- Size: tamaño de la respuesta - Inspeccionar elemento: clic derecho → "Inspeccionar"
- Editar HTML: doble clic en cualquier tag
- Editar CSS: panel "Styles" a la derecha
- Add/remove clases: panel "Styles" → .cls
- Ver computed styles: pestaña "Computed" - Abre el panel Performance
- Haz clic en Record (círculo rojo)
- Ejecuta la función en la Console
- Para la grabación
- Analiza el flame graph — verás dónde se gasta el tiempo - Clic derecho en el número de línea
- Selecciona "Add conditional breakpoint"
- Escribe la condición: i === 5
- Ejecuta la función — solo se pausará cuando i sea 5 - Ctrl+Shift+M — activar device toolbar
- Seleccionar dispositivo: iPhone, iPad, etc.
- Custom dimensions para tamaños específicos
- Network throttling para simular conexión lenta
- Rotar entre portrait y landscape - Crea el Bug Hunter Dashboard completo
- Añade los 3 bugs adicionales
- Usa solo DevTools para encontrar y arreglar cada uno
- Cronometra cuánto tardas en cada bug
- Documenta qué herramienta usaste para cada problema - ✅ Debuggear con breakpoints
- 🔍 Inspeccionar DOM y CSS en vivo
- 🌐 Analizar peticiones de red
- ⚡ Medir performance
- 🧠 Detectar memory leaks