Obtener datos experimentales mediante la API fetch
Hasta ahora hemos aprendido a calcular datos experimentales con JavaScript y a leer y escribir archivos en un entorno de servidor con Node.js. Sin embargo, todos esos datos se introducían directamente en el código o se leían desde archivos locales. En la investigación real, los datos residen en servidores externos: buscamos información genética en NCBI, recuperamos listas de muestras desde LIMS internos y obtenemos estructuras proteicas mediante APIs públicas.
Este proceso es exactamente Ajax. Es como enviar una muestra a un laboratorio externo de secuenciación: en lugar de quedarse esperando pasivamente en el laboratorio hasta que lleguen los resultados, se continúa con otros experimentos y se revisan los datos cuando llegan. En la web ocurre lo mismo: se solicita información al servidor y, mientras tanto, el navegador sigue funcionando sin detenerse; cuando llega la respuesta, se actualiza la pantalla.
fetch: realizar una solicitud de datos al servidor
fetch() es una función que envía una solicitud al servidor para obtener datos, similar a ingresar un nombre de gen en NCBI y presionar el botón de búsqueda.
fetch("https://api.example.com/gene/TP53")
.then(function(response) {
return response.text();
})
.then(function(data) {
console.log(data);
});
console.log("Solicitud enviada; continuar con otras tareas");Este código funciona en tres pasos:
fetch(url)— Envía una solicitud al servidor.then(function(response) { ... })— Programa la tarea que se ejecutará cuando llegue la respuesta.then(function(data) { ... })— Recibe y procesa los datos
La clave es la programación. fetch pasa directamente a la siguiente línea sin esperar la respuesta. Por lo tanto, "Solicitud enviada; continuar con otras tareas" se imprime primero, y el código dentro de .then se ejecuta solo después de que llega la respuesta del servidor.
Asincronía: La A de Ajax
La letra más importante en Ajax es la A al principio: Asynchronous (Asíncrono).
Usemos como analogía una solicitud de análisis genético:
// Con un enfoque síncrono (Synchronous):
// 1. Enviar la muestra a la empresa de secuenciación
// 2. Esperar cinco días en el laboratorio sin hacer nada hasta recibir el resultado
// 3. Cuando llega el resultado, comenzar entonces el siguiente experimento
// → aprovechamiento pésimo del laboratorio
// Enfoque asíncrono (Asynchronous): así se trabaja en la práctica
// 1. Enviar la muestra a la empresa de secuenciación
// 2. Mientras se espera, cultivar células, preparar tampones y leer artículos
// 3. Recibir el aviso del resultado → revisarlo y continuar con el siguiente paso
// → aprovechamiento óptimo del laboratorioVeamos esto con código:
function showGeneInfo() {
console.log("Información del gen recibida");
}
fetch("https://api.example.com/gene/BRCA1").then(showGeneInfo);
console.log(1);
console.log(2);Resultado de la ejecución:
1
2
Información del gen recibidaPrimero se muestran 1 y 2. Esto se debe a que fetch simplemente envía una solicitud al servidor y pasa inmediatamente a la siguiente línea. Más adelante, cuando llega la respuesta del servidor, se ejecuta showGeneInfo. Mientras el navegador descarga los datos, la función de desplazamiento, los clics y la entrada de datos siguen funcionando correctamente. Esta es la ventaja de la asincronía.
Reducir la cantidad de código con funciones anónimas
La función con el nombre showGeneInfo se utiliza solo una vez dentro de .then. En este caso, se puede insertar directamente sin asignarle un nombre:
// Función con nombre
function showResult() {
console.log("Resultado recibido");
}
fetch("https://api.example.com/gene/TP53").then(showResult);
// Versión abreviada con una función anónima: mismo comportamiento
fetch("https://api.example.com/gene/TP53").then(function() {
console.log("Resultado recibido");
});La función que se encuentra dentro de .then recibe automáticamente el resultado enviado por el servidor. El nombre de la variable que almacenará este resultado puede ser definido libremente; por convención, se suele usar response:
fetch("https://api.example.com/gene/TP53")
.then(function(response) {
console.log(response);
});Imaginen que un informe de experimento llega en un sobre. response es ese sobre: contiene no solo los datos reales, sino también metadatos como "el estado de la entrega".
Objeto Response: Examinando el contenido
response contiene información detallada sobre los resultados de la comunicación:
fetch("https://api.example.com/gene/TP53")
.then(function(response) {
console.log(response.status); // 200 (correcto)
console.log(response.ok); // true
});Atributos principales:
status— Código de estado HTTP.200indica éxito;404indica que no hay datos disponibles.ok— Si el código de estado está en el rango de 200 a 299, entoncestrue.
Se puede verificar primero el estado de la respuesta antes de procesarla, de forma similar a una inspección de control de calidad:
fetch("https://api.example.com/gene/TP53")
.then(function(response) {
if (response.status === 404) {
console.log("No se pudo encontrar ese gen");
} else if (response.status === 200) {
console.log("Datos recibidos correctamente");
}
});
console.assert(200 >= 200 && 200 <= 299, "200 está en el intervalo de éxito");
console.assert(404 < 200 || 404 > 299, "404 está fuera del intervalo de éxito");JSON: Formato estándar para los datos experimentales
Los datos que se reciben del servidor suelen estar en formato JSON (Notación de Objetos de JavaScript). De forma similar a como en un laboratorio se registra toda la información de las muestras siguiendo un formato predefinido, en la web, JSON cumple la función de ese formato estándar.
// Datos de un gen en formato JSON
const geneDataJson = '{"name": "TP53", "chromosome": "17p13.1", "function": "tumor suppressor", "length_bp": 19149}';
// Cadena JSON → conversión a un objeto JavaScript
const gene = JSON.parse(geneDataJson);
console.log(gene.name); // "TP53"
console.log(gene.chromosome); // "17p13.1"
console.log(gene.length_bp); // 19149
console.assert(gene.name === "TP53", "Comprobar el nombre del gen");
console.assert(typeof gene.length_bp === "number", "La longitud es de tipo numérico");Para recibir datos JSON, utiliza response.json() con fetch:
fetch("https://api.example.com/gene/TP53")
.then(function(response) {
return response.json();
})
.then(function(gene) {
console.log(gene.name); // "TP53"
console.log(gene.chromosome); // "17p13.1"
});response.text() devuelve la respuesta como una cadena de texto sin formato, mientras que response.json() analiza el JSON y lo convierte en un objeto de JavaScript. Cuando se reciben datos estructurados, como datos experimentales, casi siempre se utiliza .json().
También es común recibir datos de varias muestras en forma de matriz:
const samplesJson = '[{"id": "S001", "od": 0.85, "pass": true}, {"id": "S002", "od": 0.12, "pass": false}, {"id": "S003", "od": 1.23, "pass": true}]';
const samples = JSON.parse(samplesJson);
for (let i = 0; i < samples.length; i++) {
const status = samples[i].pass ? "PASS" : "FAIL";
console.log(`${samples[i].id}: OD=${samples[i].od} → ${status}`);
}
// S001: OD=0.85 → PASS
// S002: OD=0.12 → FAIL
// S003: OD=1.23 → PASS
console.assert(samples.length === 3, "Tres muestras");
console.assert(samples[1].pass === false, "S002 tiene estado FAIL");SPA: Aplicaciones que no recargan toda la página
Si aplicamos lo que hemos aprendido sobre fetch, podemos crear una SPA (Aplicación de Página Única). Este enfoque consiste en intercambiar solo las partes necesarias dentro de una única página HTML.
Piense en un LIMS (Sistema de Gestión de Información de Laboratorio). Al hacer clic en «Extracción de ADN» en el menú lateral, el protocolo correspondiente aparece en el área derecha; al hacer clic en «PCR», se muestra el protocolo de PCR en el mismo lugar. La página completa no se recarga, solo cambia el contenido del área principal.
function loadProtocol(name) {
fetch("https://api.example.com/protocols/" + name)
.then(function(response) {
return response.text();
})
.then(function(content) {
document.querySelector("#protocol-content").innerHTML = content;
});
}
// Cargar el protocolo correspondiente al hacer clic en el botón
// loadProtocol("dna-extraction");
// loadProtocol("pcr");Con document.querySelector("#protocol-content"), se selecciona un área específica y, con innerHTML, se reemplaza únicamente el contenido de esa área. El resto (encabezado, menú y pie de página) permanece intacto. Este es el principio fundamental de las aplicaciones de una sola página (SPA).
Un aspecto importante: al usar innerHTML, es fundamental seleccionar con precisión el área que se desea modificar. Si se selecciona el elemento padre, todos los elementos secundarios que contiene también se eliminarán. Esto es similar al error de intentar recortar y pegar solo una banda específica en una imagen de gel, pero terminar borrando las bandas adyacentes.
Separación de datos y lógica
El código de calidad separa los datos de la lógica. Si se mezcla el protocolo experimental (procedimiento) con la lista de muestras (datos) en un mismo documento, cada vez que cambian las muestras, se debe modificar el documento del protocolo, lo que aumenta el riesgo de dañar accidentalmente el procedimiento.
Lo mismo ocurre con el código. Lo ideal es tener los datos, como una lista de genes, en un archivo o servidor independiente, y que el código los cargue mediante fetch para su procesamiento:
// Datos: almacenados en un archivo JSON del servidor
// [{"name": "TP53", "type": "tumor suppressor"},
// {"name": "BRCA1", "type": "DNA repair"},
// {"name": "EGFR", "type": "receptor tyrosine kinase"}]
// Lógica: obtener los datos con JavaScript y mostrarlos en pantalla
fetch("https://api.example.com/genes")
.then(function(response) {
return response.json();
})
.then(function(genes) {
let listHtml = "";
for (let i = 0; i < genes.length; i++) {
listHtml += "<li>" + genes[i].name + " — " + genes[i].type + "</li>";
}
document.querySelector("#gene-list").innerHTML = listHtml;
});Incluso si el número de genes aumenta a 100, no será necesario modificar ninguna línea del código JavaScript. Solo hay que actualizar los datos JSON del servidor.
Prueba por ti mismo (Ejemplo simplificado)
Completa los espacios en blanco a continuación para completar el código que obtiene la información genética del servidor y la muestra en pantalla.
fetch("https://api.example.com/gene/TP53").then(function() {return response.json();}).then(function(gene) {const info = gene.name + " (" + gene. + ")";document.querySelector("#result").innerHTML = ;});
Errores comunes y soluciones
P: ¿Cómo puedo usar una variable creada dentro de .then fuera de su ámbito?
response y gene solo existen dentro de la función .then. Si intentas acceder a ellas desde fuera, se producirá un error undefined. Todo el código que utilice estos datos debe estar dentro de .then, ya que los resultados asíncronos deben procesarse cuando estén disponibles.
P: He obtenido un error al ejecutar response.json().
Esto ocurre cuando la respuesta del servidor no tiene un formato JSON válido. Primero, obtén la respuesta con response.text() y verifica el contenido real con console.log. Es posible que recibas una página de error HTML o una respuesta vacía.
P: La solicitud fetch no funciona (error CORS).
Si ves un error relacionado con "CORS" en la consola del navegador, significa que el servidor no permite el acceso desde tu dominio. Inicia un servidor de desarrollo local (npx serve) para realizar solicitudes fetch a archivos del mismo servidor, o utiliza una API pública que permita CORS.
P: ¿Cuál es la diferencia entre =, === y ==?
= se utiliza para la asignación (asignar un valor), === para la comparación estricta (comprobar si el tipo y el valor son iguales) y == para la comparación flexible (comparar después de la conversión de tipo). En las sentencias condicionales, como en if (response.status === 200), siempre utiliza ===.