- Aprender
- Informática
- Programación
- Programación en JavaScript
- Fetch y API del navegador
Fetch y API del navegador: obtención de datos
fetch, mostrar los resultados en una página web y almacenar pequeñas cantidades de datos en el navegador. Interpreta solicitudes y respuestas HTTP y datos JSON, maneja los estados de carga y de error, y da formato a fechas y precios de una API para cada lector. Descubre por qué se producen errores de CORS y por qué las claves secretas de API no deben estar en el código del cliente. Después, usa localStorage, sessionStorage y funciones del navegador como la geolocalización y el portapapeles.PrincipianteUnidad 8 de 9 del curso Curso de Programación en JavaScript
Lo que aprenderás
- Explica cómo funcionan una solicitud y una respuesta HTTP, carga datos JSON con
fetchy envía datos a una API con el método, las cabeceras y el cuerpo adecuados.- Interpreta solicitudes y respuestas HTTPDescribe las partes de una solicitud y una respuesta HTTP, relaciona cada método HTTP con la acción que realiza e interpreta los códigos de estado y las cabeceras en las herramientas de desarrollo del navegador.
- Carga datos JSON con fetchLlama a
fetch, comprueba el estado de la respuesta, lee y analiza el cuerpo JSON y construye URL de solicitud con parámetros de consulta correctamente codificados. - Envía datos con POST, PUT, PATCH y DELETEPasa un objeto de opciones a
fetchpara enviar JSON o datos de formulario y maneja la respuesta del servidor después de crear, actualizar o eliminar un registro.
- Interpreta solicitudes y respuestas HTTP
- Convierte resultados de una API en contenido de la página, da formato a fechas e importes monetarios para el lector y mantén la página clara mientras los datos se cargan, falla la carga o los datos llegan fuera de orden.
- Renderiza los resultados de una API en la páginaConstruye elementos de página a partir de los arrays y objetos de una respuesta JSON, inserta de forma segura el texto de la API y maneja campos ausentes, resultados vacíos y resultados paginados.
- Da formato a fechas, números e importes monetarios procedentes de una APIConvierte las cadenas de fecha, marcas de tiempo e importes que envían las API en texto legible para el idioma, la región y la zona horaria del lector con los formateadores de
Intl. - Muestra estados de carga, de error y sin datosHaz seguimiento de las etapas de una solicitud, muestra al usuario un mensaje claro para cada etapa y recupérate de los fallos mediante reintentos.
- Cancela solicitudes, establece tiempos límite y combina solicitudesCancela solicitudes que ya no se necesitan, establece tiempos límite, evita que las respuestas obsoletas sustituyan a las más recientes y ejecuta varias solicitudes en paralelo o en secuencia.
- Renderiza los resultados de una API en la página
- Explica la política del mismo origen y los errores de CORS, y protege las claves de API y los datos de los usuarios cuando una página se comunica con otros servidores.
- Comprende la política del mismo origen y CORSIdentifica el origen de una URL, explica por qué el navegador bloquea algunas respuestas de otros orígenes y reconoce cómo las cabeceras CORS y las solicitudes de verificación previa permiten que un servidor las autorice.
- Protege las claves de API y los datos de los usuariosExplica para qué sirven las claves de API y los tokens, por qué un secreto en el código del cliente es público y cómo enviar credenciales y manejar los datos de los usuarios de forma responsable.
- Comprende la política del mismo origen y CORS
- Guarda, lee y actualiza pequeñas cantidades de datos con localStorage y sessionStorage, y decide qué es razonable y seguro conservar en el navegador.
- Guarda y lee datos con localStorage y sessionStorageUsa los métodos de Web Storage, explica cuánto dura cada tipo de almacenamiento y quién puede leerlo, y convierte números, booleanos y objetos a cadenas almacenadas y de nuevo a sus tipos originales.
- Usa el almacenamiento del navegador en una aplicaciónRestaura el estado guardado cuando se carga una página, almacena respuestas de API en caché con un tiempo de caducidad, mantén las pestañas sincronizadas y decide qué no se debe almacenar.
- Guarda y lee datos con localStorage y sessionStorage
- Detecta y usa API del navegador que necesitan una página segura o el permiso del usuario, como la geolocalización y el portapapeles, y ofrece a los usuarios una alternativa cuando una función no esté disponible.
- Obtén la ubicación del usuario con la API de geolocalizaciónComprueba que una API del navegador está disponible, explica los contextos seguros y las solicitudes de permiso, y usa la API de geolocalización con sus opciones, errores y una alternativa de respaldo.
- Copia texto y usa otras API del navegadorCopia texto con la API del portapapeles, responde a cambios de conectividad, lee parámetros de la dirección de la página y sigue un método para aprender cualquier API nueva del navegador.
- Obtén la ubicación del usuario con la API de geolocalización
Guía de estudio de Fetch y API del navegador
1Haz solicitudes e interpreta las respuestas
Una página puede pedir datos a un servidor sin cargar una página nueva. La solicitud indica qué recurso quieres y qué quieres hacer con él; la respuesta te dice qué ha ocurrido. Seguirás ese intercambio en la pestaña Network, convertirás una respuesta JSON en datos de JavaScript y enviarás cambios al servidor. Los puntos de comprobación importantes son el método, el estado y la estructura del cuerpo: recibir una respuesta no significa por sí solo que la operación haya tenido éxito.
1.1 Las partes de un intercambio HTTP
Una API web permite que un programa lea o modifique datos mediante URL identificadas llamadas puntos de acceso. El JavaScript de la página es el cliente. Envía una solicitud HTTP; el servidor responde con una respuesta HTTP. Muchas API envían texto JSON, que puede representar objetos, arrays, cadenas de caracteres, números, booleanos y null.
Interpreta una solicitud
Considera GET https://api.example.com/books?author=Le%20Guin&limit=5. El método es GET, la ruta /books selecciona el recurso y la cadena de consulta contiene dos parámetros. El valor de author es «Le Guin»; %20 codifica el espacio. Un signo & separa los parámetros. La documentación de la API explica qué nombres de parámetros acepta y qué significa cada valor.
Una solicitud también puede llevar cabeceras, que son pares de nombre y valor, y un cuerpo, que contiene los datos enviados. Accept: application/json solicita una respuesta JSON. Content-Type: application/json describe el cuerpo que se envía. Authorization transporta credenciales. Los nombres de las cabeceras no distinguen mayúsculas de minúsculas, así que content-type y Content-Type identifican la misma cabecera.
Elige la acción
| Método | Acción prevista | Uso habitual |
|---|---|---|
GET | Leer | Obtener una lista de notas |
POST | Crear o enviar | Añadir una nota |
PUT | Sustituir | Enviar la nota completa de reemplazo |
PATCH | Modificar una parte | Marcar una nota como completada |
DELETE | Eliminar | Eliminar una nota |
GET y HEAD son métodos seguros: su finalidad prevista es leer, así que no uses GET para un botón de eliminación. GET, PUT y DELETE son idempotentes. Repetir la misma solicitud deja el servidor en el mismo estado previsto que ejecutarla una vez. Eliminar una nota ya eliminada puede devolver un estado distinto, pero la nota sigue ausente. Repetir un POST puede crear un segundo registro.
Interpreta la respuesta
La respuesta contiene un código de estado, cabeceras y normalmente un cuerpo. El primer dígito agrupa el resultado:
- 2xx: éxito.
200 OKsuele tener datos,201 Createdinforma de una creación y204 No Contentno tiene cuerpo. - 3xx: redirección. De forma predeterminada,
fetchsigue las redirecciones. - 4xx: un problema con la solicitud o el acceso.
400significa solicitud incorrecta;401significa credenciales ausentes o no válidas;403significa que el servidor entiende la solicitud pero la rechaza;404significa que no se encontró;429significa que hay demasiadas solicitudes. - 5xx: un problema del servidor, como
500 Internal Server Erroro503 Service Unavailable.
Una llamada a /books/42 podría devolver 200, un tipo de contenido JSON y {"id":42,"title":"The Dispossessed","year":1974}. Una llamada a /books/9999 podría devolver 404 y {"error":"Book not found"}. Ambas llamadas recibieron una respuesta. Un fallo de conexión no produce ningún estado HTTP que JavaScript pueda examinar.
Inspecciona antes de hacer suposiciones
Abre las herramientas de desarrollo, selecciona Network y desencadena la acción. Inspecciona el método, la URL completa, el estado, las cabeceras, el cuerpo y los tiempos. Compáralos con el punto de acceso, los parámetros obligatorios, las credenciales, los límites de frecuencia y la respuesta de ejemplo de la documentación. Si el servidor devolvió los datos correctos, investiga el código de la página; si la URL de la solicitud es incorrecta, corrígela antes de modificar el código de renderizado.
Puntos clave
- Un punto de acceso es una URL que una API expone para una operación.
- El método selecciona la acción; la URL selecciona el recurso y los parámetros.
- Las cabeceras de solicitud y respuesta describen el intercambio.
- Un
404es una respuesta, mientras que un fallo de conexión no tiene estado HTTP. - Inspecciona la pestaña Network y compara el intercambio con la documentación de la API.
1.2 Carga JSON en dos pasos asíncronos
fetch(url) envía una solicitud GET y devuelve una promesa. Su resultado es un objeto Response, disponible cuando llegan las cabeceras. Leer el cuerpo es una operación asíncrona independiente. response.json() lee ese cuerpo y lo analiza para convertirlo en datos de JavaScript.
Espera, comprueba y lee
async function loadBook(id) {
const response = await fetch(`https://api.example.com/books/${id}`);
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
return await response.json();
}
Para loadBook(42), el primer await obtiene la respuesta. La condición rechaza un resultado HTTP fallido. El segundo await obtiene el libro analizado, como { id: 42, title: "The Dispossessed", year: 1974 }. La propia función devuelve una promesa, por lo que quien la llama también espera el resultado.
response.ok es verdadero para los estados de 200 a 299. Un error HTTP como 404 o 500 no rechaza la promesa de fetch: un servidor respondió. Un fallo de red, un intercambio bloqueado por CORS, una URL de solicitud no válida o una cancelación pueden rechazarla. Lanzar un error ante !response.ok permite que un try/catch que lo rodee maneje también los fallos HTTP.
Comprende el cuerpo
Sin await, const data = response.json() almacena una promesa, no el libro. Acceder entonces a data.title da undefined. Omitir await en fetch deja igualmente una promesa donde el código espera un Response.
Elige el lector de cuerpo adecuado para la respuesta: json() para JSON, text() para texto o blob() para datos binarios. Un cuerpo solo se puede consumir una vez. Guarda el resultado analizado y reutilízalo. Para inspeccionar también el texto JSON sin procesar, lee text() una vez y después llama a JSON.parse(text) sobre esa cadena guardada.
Un JSON no válido se rechaza con un SyntaxError. Una página HTML de error suele causar un mensaje «Unexpected token '<'». Un cuerpo vacío, incluido el de una respuesta 204, tampoco se puede analizar como JSON. Comprueba primero el estado e inspecciona response.headers.get("Content-Type") cuando tengas dudas sobre el formato. Un estado de éxito por sí solo no garantiza un cuerpo JSON.
Construye una consulta de forma segura
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "rock & roll");
url.searchParams.set("limit", 10);
La dirección resultante es https://api.example.com/search?q=rock+%26+roll&limit=10. El signo & incluido se codifica como parte del valor. Unir la entrada a "?q=" puede dar a &, # o + sus significados en una URL y cambiar la búsqueda. Una URL relativa sigue la resolución normal de direcciones: desde https://notes.example.org/app/index.html, fetch("data/books.json") carga /app/data/books.json en ese origen.
Sigue la estructura devuelta
Para {"results":[{"title":"Dune"}],"total":1}, el primer título es data.results[0].title. El objeto exterior no es el array de resultados. Usa la vista previa de la respuesta para encontrar el array antes de recorrerlo.
Una función auxiliar compartida getJSON(url, options) puede realizar la misma comprobación de estado y lectura del cuerpo para muchas llamadas. En una cadena .then(), devuelve response.json() desde la función de devolución de llamada de la respuesta para que la siguiente reciba los datos analizados. Añade .catch() al final para manejar los pasos rechazados.
Puntos clave
fetchyresponse.json()devuelven promesas separadas.- Comprueba
response.ok; un error HTTP no hace quefetchse rechace. - Lee el cuerpo de una respuesta una sola vez y reutiliza el valor guardado.
- Usa
URL.searchParamspara codificar los valores de consulta. - Lee el JSON anidado según su estructura real de objetos y arrays.
- Una respuesta correcta puede contener un cuerpo JSON vacío o no válido.
1.3 Envía un cambio y usa el resultado del servidor
El segundo argumento de fetch configura una solicitud. Sus opciones incluyen method, headers, body, signal y credentials. Sin estas opciones, la solicitud es un GET sin cuerpo. Para enviar JSON, debes preparar tanto su texto como su tipo de contenido.
Envía JSON
const response = await fetch("https://api.example.com/notes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Shopping", text: "Rice, lentils" }),
});
JSON.stringify produce {"title":"Shopping","text":"Rice, lentils"}. La cabecera indica al servidor cómo leer ese texto. Pasar el objeto directamente como cuerpo envía "[object Object]". Enviar la cadena JSON sin la cabecera la etiqueta como text/plain;charset=UTF-8, que muchos puntos de acceso JSON rechazan con 400 o 415 Unsupported Media Type.
Una creación correcta suele devolver 201 con el registro almacenado, como {"id":17,"title":"Shopping","text":"Rice, lentils"}. Usa este objeto devuelto para actualizar la página: el nuevo id del servidor es necesario para ediciones y eliminaciones posteriores.
Sustituye o actualiza
| Solicitud | Cuerpo | Significado |
|---|---|---|
PATCH /notes/17 | {"done":true} | Modificar el campo proporcionado |
PUT /notes/17 | La nota completa de reemplazo | Sustituir el recurso |
DELETE /notes/17 | A menudo ninguno | Eliminar el recurso |
Un cuerpo de PUT que omite un campo puede hacer que ese campo se elimine o restablezca, según la API. Usa el método documentado para el cambio previsto. PUT y PATCH pueden devolver un registro actualizado con 200 o devolver 204 sin cuerpo.
Maneja el éxito sin suponer que siempre habrá JSON a continuación:
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
const saved = response.status === 204
? null
: await response.json();
Este patrón sirve para puntos de acceso documentados para devolver JSON o 204. Una eliminación puede tener éxito y aun así producir un error de análisis sintáctico si el código llama a json() sobre su cuerpo vacío sin comprobarlo.
Elige el formato del cuerpo
new FormData(formElement) recopila los campos con nombre de un formulario y los archivos seleccionados. Pásalo directamente como body. Deja que el navegador establezca Content-Type: multipart/form-data y su delimitador; una cabecera proporcionada manualmente puede omitir el delimitador necesario para separar los campos. Un cuerpo URLSearchParams usa application/x-www-form-urlencoded.
GET y HEAD no pueden llevar un cuerpo mediante fetch. Pon los términos de búsqueda y los filtros en la cadena de consulta de la URL. Intentar un GET con cuerpo se rechaza con un TypeError antes de que pueda servir como solicitud de búsqueda.
Termina de forma segura tras el éxito o el fallo
Desactiva el botón de envío antes de esperar una solicitud de creación y vuelve a activarlo en finally. De lo contrario, un doble clic puede enviar dos solicitudes POST y crear dos registros. No repitas automáticamente una operación de creación cuyo resultado sea incierto: una respuesta perdida no determina si el servidor hizo el cambio.
Para un estado de error, el cuerpo puede contener un mensaje útil como {"error":"title is required"}. Léelo una vez si es JSON; captura un fallo de análisis y conserva un mensaje HTTP general para respuestas vacías o HTML. Mantén disponible el texto introducido por el usuario para que pueda corregir la solicitud.
Puntos clave
- Las solicitudes JSON necesitan
JSON.stringifyy un tipo de contenido correspondiente. - Usa
PATCHpara una modificación parcial yPUTpara una sustitución completa. - Omite el análisis de JSON para
204 No Content. - Deja que el navegador establezca la cabecera multiparte al enviar
FormData. - Usa la respuesta del servidor, incluido el ID que asignó, para actualizar la página.
- Evita envíos duplicados y restablece los controles en
finally.
2Convierte las respuestas en una página útil
Obtener datos es solo la primera parte de una interfaz. Los lectores necesitan resultados útiles, fechas y precios legibles, y un mensaje claro mientras esperan. Construirás la presentación a partir de la estructura de la respuesta, evitarás que los valores ausentes la hagan fallar y mostrarás el éxito, los resultados vacíos y los fallos. También controlarás las solicitudes simultáneas para que una respuesta lenta no pueda sustituir resultados más recientes, y elegirás cuándo pueden ejecutarse juntas las solicitudes independientes.
2.1 Construye la presentación a partir de datos
El renderizado convierte un array o un objeto en elementos de la página. Guarda los datos obtenidos en una variable y pásalos a una función de renderizado. Esa separación permite ordenar o filtrar los mismos datos sin volver a pedirlos al servidor.
Crea un elemento por cada resultado
function renderBooks(books, list) {
list.replaceChildren();
for (const book of books) {
const item = document.createElement("li");
item.textContent = `${book.title} (${book.year})`;
list.append(item);
}
}
Para [{"title":"Kindred","year":1979},{"title":"Beloved","year":1987}], esto crea dos elementos de lista: «Kindred (1979)» y «Beloved (1987)». Vaciar primero el contenedor hace que una nueva búsqueda sustituya a la anterior. Sin ese paso, las listas antigua y nueva se acumulan.
Mantén el texto externo como texto
Usa textContent para títulos, descripciones y otros textos de la API. innerHTML analiza una cadena como marcado. Un título que contenga <img src="x" onerror="alert(1)"> puede entonces ejecutar código. Esto son secuencias de comandos entre sitios, o XSS. El texto de formularios y almacenamiento necesita el mismo tratamiento porque también puede proceder de una fuente no confiable.
Las propiedades de los elementos establecen valores individuales, como img.alt = book.title. No hacen que todo tipo de valor sea seguro automáticamente. Un enlace proporcionado por una API sigue necesitando una comprobación del protocolo:
try {
const target = new URL(book.url, location.href);
if (target.protocol === "https:" || target.protocol === "http:") {
link.href = target.href;
}
} catch {
link.removeAttribute("href");
}
Este código se ejecuta sobre un enlace recién creado que no tiene un href. Una URL no válida o no permitida lo deja sin destino. Una URL javascript: no es navegación web normal. Para las imágenes, proporciona un texto alt significativo construido a partir de los datos cuando sea posible.
Proporciona valores predeterminados sin perder valores reales
Los campos opcionales pueden estar ausentes o ser null. book.author?.name ?? "Unknown author" primero intenta obtener el nombre anidado y después proporciona un valor predeterminado. El encadenamiento opcional evita acceder a una propiedad de un autor ausente.
El operador importa: 0 || "n/a" da "n/a", mientras que 0 ?? "n/a" conserva 0. El operador || sustituye todos los valores falsos en contexto booleano, incluidos el cero y una cadena vacía; ?? solo sustituye null y undefined. Un libro con cero ejemplares disponibles debe mostrar cero.
Un array de resultados vacío es una búsqueda correcta sin coincidencias. Muestra «Ningún libro coincide con tu búsqueda» para que los lectores puedan distinguirlo de una página que no se ha cargado.
Sustituye una búsqueda, añade otra página
Muchas API devuelven páginas usando page, limit, un recuento total o una URL next. Con 47 resultados y 10 por página, cuatro páginas completas contienen 40 registros y la quinta contiene 7. Una nueva búsqueda borra la lista anterior; «Cargar más» añade la siguiente página a la lista actual. Mantén separadas esas dos acciones de presentación.
Para ordenar una copia local con los más recientes primero, usa [...books].sort((a, b) => b.year - a.year) y renderiza esa copia. La propagación crea un array nuevo, por lo que el orden de la respuesta guardada sigue disponible. Inspecciona la estructura de la respuesta antes de seleccionar el array: una API paginada suele colocarlo dentro de data.results.
Puntos clave
- Renderiza a partir de datos guardados para que la ordenación local no necesite una nueva solicitud.
- Inserta texto no confiable con
textContent. - Valida el protocolo de un enlace de API antes de asignar su destino.
- Usa
?.para datos anidados ausentes y??cuando el cero deba seguir siendo cero. - Sustituye los resultados para una nueva búsqueda; añade resultados para otra página.
2.2 Da formato a fechas e importes para las personas
Las API devuelven valores que los programas pueden intercambiar fácilmente. Los lectores necesitan fechas, horas e importes con formato para su idioma y región. Mantén el valor almacenado separado del texto usado para mostrarlo.
Lee primero el formato de fecha
"2026-03-05T14:30:00Z" designa un instante: las 14:30 UTC del 5 de marzo de 2026. La Z significa UTC. new Date(...) lo convierte en un Date de JavaScript. Una cadena con solo la fecha, como "2026-03-05", se interpreta como medianoche UTC; una fecha y hora sin desplazamiento, como "2026-03-05T14:30", se interpreta como hora local.
Una marca de tiempo Unix cuenta desde el 1 de enero de 1970, UTC. Las API suelen contar segundos, pero Date recibe milisegundos. new Date(1772721000 * 1000) da el mismo instante del 5 de marzo. Omitir la multiplicación da una fecha de enero de 1970. Lee la documentación de la API para identificar la unidad.
Elige una configuración regional y una zona horaria
const date = new Date("2026-03-05T14:30:00Z");
const dateFormat = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short",
timeZone: "UTC",
});
dateFormat.format(date);
La salida es «Mar 5, 2026, 2:30 PM». Con en-GB, es «5 Mar 2026, 14:30». El uso de fechas cortas produce «3/5/26» en en-US, «05/03/2026» en en-GB y «05.03.26» en de-DE.
La configuración regional controla la presentación; la zona horaria controla la hora local. Sin timeZone, el formateador usa la zona del dispositivo. Ese instante corresponde a las 9:30 de la mañana en Nueva York, las 15:30 en Ámsterdam y las 11:30 de la noche en Tokio. Conserva y envía los instantes en UTC y conviértelos para mostrarlos. Una fecha de calendario como un cumpleaños requiere cuidado: dar formato a la medianoche UTC en una zona al oeste de UTC puede mostrar el día anterior.
Mantén la moneda separada de la configuración regional
const priceFormat = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
});
priceFormat.format(1234.5);
Esto da €1,234.50. Para el mismo importe, de-DE con EUR da 1.234,50 €; en-US con USD da $1,234.50; en-US con JPY da ¥1,235. JPY no tiene unidad monetaria fraccionaria, por lo que su presentación habitual no tiene decimales. Seleccionar una configuración regional no convierte entre monedas. Usa el código de moneda proporcionado con el importe.
Algunas API de pagos envían unidades fraccionarias enteras. Con USD, 1999 centavos significan 19.99 dólares: divide entre 100 antes de darles formato. No apliques ese divisor a JPY. Sumar centavos enteros da 1999 + 2550 = 4549, que se muestra como $45.49. Esto evita el conocido resultado de la aritmética decimal 0.1 + 0.2, que es 0.30000000000000004.
Reutiliza el formateador
Crea un formateador una vez para una lista. Usa undefined como configuración regional para seleccionar la opción predeterminada del navegador; navigator.language indica la etiqueta de idioma preferida del navegador. Otras opciones dan formato a 0.256 como «26%», o a 12.5 con la unidad "kilometer-per-hour" como «12.5 km/h». new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(-1, "day") da «yesterday». Las fechas construidas a mano, como «03/05/2026», siguen siendo ambiguas entre regiones.
Puntos clave
- Comprueba si las marcas de tiempo usan segundos o milisegundos.
- Una zona horaria explícita hace previsible la presentación de fecha y hora.
- La configuración regional controla el formato; la moneda procede de los datos.
- Convierte las unidades fraccionarias documentadas antes de dar formato a los importes monetarios.
- Reutiliza los objetos formateadores de
Intlen una lista. - Las cadenas con solo fecha se interpretan como UTC y pueden cambiar de día al mostrarse en otra zona.
2.3 Muestra qué está haciendo la solicitud
Una solicitud tiene un ciclo de vida visible: inactiva, en carga y después con éxito o con error. El éxito puede contener datos o un resultado vacío. La página debe explicar cada estado para que los lectores sepan si deben esperar, cambiar una búsqueda o volver a intentarlo.
Mantén juntos la preparación y el restablecimiento
En este manejador, getJSON comprueba el estado HTTP y analiza el cuerpo, searchUrl construye la URL de la solicitud y renderResults actualiza la lista. El botón y el elemento de estado ya existen en la página.
async function search(query) {
button.disabled = true;
status.textContent = "Loading…";
try {
const data = await getJSON(searchUrl(query));
renderResults(data.results);
status.textContent = data.results.length === 0 ? "No results." : "";
} catch (error) {
status.textContent = "Could not load results. Check your connection and try again.";
console.error(error);
} finally {
button.disabled = false;
}
}
La preparación ocurre antes de la espera. La ruta de éxito renderiza los resultados y maneja un array vacío. El bloque catch sustituye el mensaje de carga si falla algún paso esperado. finally restablece el botón después de cualquiera de las dos rutas. Si el restablecimiento apareciera solo después de un await correcto, un fallo dejaría el control desactivado.
Explica la causa de forma útil
Un error HTTP tiene un estado que orienta el mensaje. Para 404, indica que no se encontró el elemento. Para 401, pide al usuario que inicie sesión; para 403, explica que no se permite el acceso. Para 429, pídele que espere. Para 5xx, explica que el servicio tiene un problema y sugiere intentarlo más tarde.
Un TypeError de fetch puede significar un fallo de red, una solicitud CORS bloqueada o una URL incorrecta. JavaScript no recibe un diagnóstico detallado fiable de CORS; inspecciona la consola del navegador y la pestaña Network. Un SyntaxError de json() apunta a un JSON no válido. Las cancelaciones y los tiempos límite producen errores como AbortError y TimeoutError. Conserva los detalles técnicos en la consola y ofrece a los lectores una acción que puedan entender.
Haz visibles los cambios
Usa un elemento de estado existente como <p role="status"></p>. Sus cambios se anuncian a los lectores de pantalla sin mover el foco. aria-live="polite" cumple una finalidad similar; role="alert" es adecuado para errores urgentes. Un indicador giratorio por sí solo no comunica un resultado vacío ni una solicitud fallida.
Un botón Reintentar vuelve a llamar a la función de carga. Reintentar solicitudes 400 o 404 sin cambios suele repetir el problema. Los fallos temporales de red o de servicio pueden justificar una secuencia breve y limitada de reintentos. La espera exponencial entre reintentos aumenta la pausa, por ejemplo 1 segundo, 2 segundos y después 4 segundos. Respeta la cabecera de respuesta Retry-After; puede indicar un retraso en segundos o una fecha HTTP. Evita reintentar automáticamente una solicitud de creación que podría haber tenido éxito.
Si falla una actualización pero los datos anteriores siguen siendo útiles, mantenlos visibles con una nota como «Se muestran los resultados de las 10:42. No se pudieron actualizar». No hagas que los resultados antiguos parezcan actuales sin avisar.
Prueba las situaciones difíciles
Usa las herramientas de desarrollo para ralentizar la conexión, desconectarte y solicitar una ruta que no existe. Comprueba que la carga aparezca rápidamente, que una solicitud fallida la sustituya, que un resultado correcto vacío tenga su propio mensaje y que los controles vuelvan a poder usarse.
Puntos clave
- Haz visibles la carga, el éxito sin datos, el éxito con datos y los errores.
- Coloca el restablecimiento compartido en
finally. - Ofrece a los lectores una acción útil y conserva los detalles técnicos en la consola.
- Anuncia las actualizaciones de estado mediante una región activa adecuada.
- Limita los reintentos y respeta la espera solicitada por el servidor.
2.4 Controla las solicitudes simultáneas y en paralelo
Las solicitudes pueden continuar después de la acción que las inició. Una respuesta de búsqueda puede llegar después de que el lector haya escrito otra cosa, y un servicio lento puede dejar una página esperando demasiado tiempo. Controla qué resultados siguen siendo pertinentes, además de si cada solicitud tuvo éxito.
Cancela el trabajo que ya no necesitas
Crea un AbortController, pasa su signal a fetch y llama a abort() para cancelar la solicitud. La cancelación puede interrumpir tanto la espera de las cabeceras como una lectura del cuerpo en curso. El rechazo normalmente se llama "AbortError".
const controller = new AbortController();
const response = await fetch(url, { signal: controller.signal });
// A cancel button can call controller.abort().
const data = await response.json();
Rodea ambas esperas de un manejo de errores. Si tu código cancela una búsqueda obsoleta a propósito, retorna sin avisar para esa cancelación esperada, en lugar de decir al usuario que el servicio falló.
fetch no tiene una opción timeout integrada. Usa una señal como AbortSignal.timeout(5000) para limitar la solicitud a 5000 ms, o 5 segundos de tiempo activo. Antes de que lleguen las cabeceras, se rechaza con TimeoutError; después de que lleguen, puede interrumpir la lectura del cuerpo.
Evita que prevalezcan las búsquedas antiguas
Una condición de carrera ocurre cuando el orden en que terminan las operaciones cambia el resultado. Un lector escribe «ca» y después «cat». Si «ca» llega la última y se renderiza, la pantalla deja de coincidir con la entrada.
Una opción cancela la solicitud anterior antes de cada nueva solicitud. Otra asigna un número a cada llamada y solo permite que la más reciente actualice la página:
let latest = 0;
async function search(query) {
const request = ++latest;
try {
const data = await getJSON(searchUrl(query));
if (request !== latest) return;
renderResults(data.results);
} catch (error) {
if (request !== latest) return;
showError(error);
}
}
La comprobación también impide que un fallo antiguo sustituya un éxito más reciente. Aplica la misma comprobación de pertinencia a los mensajes de carga y al restablecimiento de los controles cuando las llamadas se solapen.
La agrupación de llamadas tras un periodo de inactividad reduce el número de llamadas que se inician. Cancela el temporizador anterior en cada pulsación e inicia uno nuevo, por ejemplo de 300 ms. Al escribir «paris» rápidamente se inicia una solicitud después de la pausa. Esta agrupación ahorra solicitudes; por sí sola no impide que una respuesta anterior aún en curso llegue tarde.
Decide qué puede ejecutarse al mismo tiempo
Las solicitudes independientes pueden iniciarse juntas:
const [user, posts] = await Promise.all([
getJSON(userUrl),
getJSON(postsUrl),
]);
Para duraciones de 300 ms y 500 ms, las dos tardan unos 500 ms en lugar de unos 800 ms en secuencia. Promise.all se rechaza en cuanto se rechaza una de las promesas de entrada, pero no cancela las demás operaciones.
Usa Promise.allSettled cuando los resultados parciales sean útiles. Espera a todas las promesas de entrada e informa de cada una como { status: "fulfilled", value } o { status: "rejected", reason }. Un panel de control puede mostrar entonces las secciones que tuvieron éxito junto a una que falló.
Las solicitudes dependientes deben permanecer en secuencia. Si una segunda URL necesita un ID devuelto por la primera solicitud, espera ese ID antes de construir la segunda solicitud.
Puntos clave
- Pasa una señal de cancelación antes de llamar a
abort(). - Captura los errores tanto de la obtención como de la lectura del cuerpo.
- Ignora los resultados y los errores obsoletos.
- La agrupación tras una pausa reduce las llamadas; una comprobación de pertinencia evita actualizaciones obsoletas.
- Usa
Promise.allpara trabajos independientes que deben tener éxito juntos. - Usa
Promise.allSettledcuando los resultados parciales sean útiles. - Espera los datos necesarios antes de iniciar una solicitud dependiente.
3Lee datos de otros orígenes y protege las credenciales
Una solicitud puede parecer correcta y aun así fallar en un navegador porque la página y la API pertenecen a orígenes distintos. Ese límite está controlado conjuntamente por las reglas del navegador y las cabeceras de respuesta del servidor. Identificarás el origen, interpretarás los fallos de verificación previa y de CORS, y distinguirás el permiso para leer una respuesta del permiso para realizar una acción. Las credenciales requieren una decisión aparte: el usuario puede inspeccionar todo lo que se envía a un navegador.
3.1 Comprende el límite de origen del navegador
Un origen combina el esquema, el host y el puerto de una URL. Una ruta no forma parte de él. https://shop.example.com/cart y /help en el mismo sitio comparten un origen. Cambiar a http://shop.example.com, https://api.example.com o https://shop.example.com:8443 cambia el origen. HTTPS usa normalmente el puerto 443.
¿Quién permite leer la respuesta?
La política del mismo origen limita los recursos que puede leer un script de una página. Para una solicitud fetch a otro origen, CORS permite que el servidor de la API conceda acceso mediante cabeceras de respuesta. Una página en https://notes.example.org que llama a https://api.example.com/weather necesita el permiso de la API para leer la respuesta.
Access-Control-Allow-Origin: https://notes.example.org concede acceso a ese origen. El valor * permite cualquier origen para una solicitud sin credenciales. Si la respuesta no tiene un permiso que coincida, el navegador la oculta a la página y fetch se rechaza con un TypeError. La consola proporciona el diagnóstico de CORS; JavaScript no recibe el motivo detallado.
Añadir Access-Control-Allow-Origin a la solicitud de JavaScript no concede permiso. Es una cabecera de respuesta controlada por el servidor. Añadir una cabecera de solicitud personalizada puede generar una comprobación de verificación previa adicional.
Por qué aparece OPTIONS antes de POST
Algunas solicitudes a otros orígenes necesitan una verificación previa. El navegador envía primero OPTIONS, indicando el método previsto en Access-Control-Request-Method y los nombres de las cabeceras que no están en la lista permitida en Access-Control-Request-Headers. El servidor los permite con Access-Control-Allow-Methods y Access-Control-Allow-Headers, junto con el permiso del origen.
Una solicitud básica GET, HEAD o POST con solo cabeceras permitidas puede evitar la verificación previa. Los tipos de contenido permitidos incluyen text/plain, application/x-www-form-urlencoded y multipart/form-data. Un POST JSON, una cabecera Authorization, PUT o DELETE requiere verificación previa salvo que haya un permiso anterior válido en caché. Si se rechaza la verificación previa, la solicitud real no se envía.
Para una solicitud simple, la solicitud real puede llegar al servidor aunque después el navegador bloquee la lectura de su respuesta. Por eso CORS no sustituye la autorización del servidor ni la comprobación de los datos de entrada.
Las cookies añaden otro requisito
La opción predeterminada credentials: "same-origin" envía cookies solo para solicitudes del mismo origen. credentials: "include" también permite las cookies que cumplan las condiciones en solicitudes a otros orígenes. Las reglas SameSite y las políticas de cookies de terceros siguen aplicándose.
Para permitir que JavaScript lea una respuesta con credenciales, el servidor debe enviar Access-Control-Allow-Credentials: true e indicar explícitamente el origen de la página. Access-Control-Allow-Origin: * no funciona con credenciales. Estas cabeceras no obligan a un navegador a enviar una cookie que de otro modo estaría bloqueada.
Diagnostica sin ocultar el problema
mode: "no-cors" da una respuesta opaca con estado 0 y sin cuerpo ni cabeceras legibles. No puede proporcionar JSON a una página. Que una solicitud funcione en curl tampoco demuestra que exista permiso CORS en el navegador: los clientes de terminal no aplican esa política del navegador.
Inspecciona la consola y la pestaña Network. Comprueba si falló la verificación previa o si a la respuesta final le faltaba el permiso. Corrige la configuración de respuesta de la API o dirige la llamada a través de tu propio servidor. Durante el desarrollo, sirve las páginas desde un servidor local: las páginas file:// suelen tener orígenes opacos. Un servidor local sigue necesitando permiso CORS cuando llama a un origen distinto.
Puntos clave
- Un origen consta de esquema, host y puerto.
- Las cabeceras de respuesta del servidor conceden permiso de lectura entre orígenes.
- La verificación previa comprueba el método y las cabeceras propuestos antes de la solicitud real.
- CORS puede ocultar una respuesta después de que una solicitud simple ya se haya procesado.
- Las respuestas con credenciales requieren un origen explícito y una cabecera de credenciales.
no-corsproduce una respuesta opaca, no JSON legible.
3.2 Mantén las claves secretas fuera de la página
Una clave de API identifica a una aplicación que hace llamadas para controlar el uso, los límites y la facturación. Un token de acceso concede acceso a un usuario o una sesión. Cualquiera que posea una credencial utilizable puede actuar con su autoridad, así que decide dónde debe estar antes de añadirla a una solicitud.
Las cabeceras protegen la ubicación, no el secreto frente al usuario
Los proveedores pueden exigir Authorization: Bearer <token>, X-API-Key: <key> o un parámetro de consulta como api_key. Sigue la documentación de la API. Una cabecera evita incluir la credencial en una URL completa que puede acabar en registros y herramientas de análisis. Una cabecera Authorization o personalizada en una llamada a otro origen normalmente desencadena una verificación previa.
Una cabecera sigue siendo visible en las herramientas de desarrollo. Los visitantes pueden inspeccionar el JavaScript que descargan y las solicitudes que envía. Minificar el código u ocultar un valor detrás de una variable no lo convierte en secreto.
Sigue la clave en una solicitud meteorológica
Supongamos que el código del navegador llama a https://api.weather.example/v1/current?city=Lima&key=sk_live_4f9a2c. Cualquiera que abra Network puede copiar la clave y usar la cuota de la cuenta. Trasladar ese valor a una variable de entorno de compilación no ayuda si la compilación lo inserta en el JavaScript enviado a la página.
Un secreto guardado en el servidor cambia el recorrido:
- La página llama a su propio sitio en
/api/weather?city=Lima. - El servidor de ese sitio añade el secreto y contacta con el proveedor meteorológico.
- El servidor devuelve los datos meteorológicos a la página, manteniendo el secreto fuera de la respuesta.
El servidor sigue necesitando controlar el acceso y el uso de su punto de acceso. Mantener el secreto del proveedor en un servidor no hace que el uso público ilimitado sea inofensivo.
Algunos proveedores emiten claves para navegador destinadas a ser públicas. Aplica las restricciones de dominio del proveedor, limita las API permitidas y establece cuotas de uso. Usa una clave de este modo solo cuando su diseño documentado lo permita; una clave secreta de servidor no se convierte en clave para navegador por añadir una restricción de dominio.
Responde a una exposición
Mantén los archivos de credenciales fuera del control de versiones, por ejemplo incluyendo .env en .gitignore. Esto protege el archivo para que no se incluya en un commit; no impide que una compilación del cliente publique un valor que el código incorpora. Si una clave queda expuesta, revócala y genera una de reemplazo. Eliminarla del commit más reciente deja intactos el historial anterior y las copias.
Protege el intercambio y reduce el uso innecesario
Usa HTTPS para las llamadas a API, de modo que los datos y las credenciales se cifren durante el tránsito. Una llamada fetch de una página HTTPS a una API HTTP se bloquea por contenido mixto. El cifrado no impide que la persona que usa el navegador vea su propia solicitud.
Un límite de frecuencia restringe el uso, por ejemplo a 60 solicitudes por minuto. Las llamadas que superan el límite pueden devolver 429 Too Many Requests. Almacena en caché los resultados adecuados, agrupa las llamadas de búsqueda tras una pausa en la entrada y evita llamadas duplicadas. Si el servidor proporciona Retry-After, respeta su tiempo de espera en lugar de reintentar repetidamente de inmediato.
La validación del lado del cliente facilita el uso de los formularios, pero cualquiera puede llamar a un punto de acceso sin tu formulario. El servidor debe validar las solicitudes y autorizar las acciones por sí mismo. Al mostrar su respuesta, sigue tratando las cadenas como texto no confiable e insértalas con textContent.
Puntos clave
- El código y las solicitudes enviados al navegador exponen las credenciales que contienen.
- Una clave secreta debe estar en el servidor que llama al proveedor.
- Restringe las claves públicas para navegador por dominio, API y cuota.
- Revoca una clave expuesta; eliminarla del código actual no basta.
- HTTPS cifra el tránsito, mientras que el servidor sigue validando y autorizando las solicitudes.
4Conserva pequeñas cantidades de estado en el navegador
Una configuración o un borrador pueden sobrevivir a una recarga sin una nueva solicitud al servidor. El almacenamiento del navegador lo facilita, pero sus valores son cadenas y su duración depende del almacén que elijas. Guardarás y restaurarás pequeñas partes del estado, validarás los datos antiguos antes de usarlos y darás un tiempo de caducidad a los resultados de API almacenados en caché. También decidirás qué datos deben estar en otro lugar, ya que el almacenamiento local no es una caja fuerte para secretos ni la única copia segura de trabajos importantes.
4.1 Guarda cadenas y restaura sus tipos
Web Storage ofrece dos almacenes de pares clave-valor: localStorage y sessionStorage. Usan los mismos métodos, por lo que la elección principal es cuánto deben durar los datos y qué pestañas deben compartirlos.
Elige la duración
| Almacén | Duración | Uso compartido |
|---|---|---|
localStorage | Sobrevive al cierre de la pestaña y del navegador hasta que se elimina o borra | Compartido por las páginas del mismo origen |
sessionStorage | Sobrevive a las recargas durante la sesión de página de la pestaña | Separado para cada pestaña y origen |
Cerrar la pestaña termina su almacenamiento de sesión. Una página recién abierta que tiene un control de apertura puede empezar con una copia del almacenamiento de sesión de la página que la abrió, pero los cambios posteriores permanecen separados. Evita usar el almacenamiento de sesión para mantener información en secreto frente a los scripts.
El almacenamiento sigue los orígenes. https://app.example.com no puede compartir su almacén con http://app.example.com. Las rutas del mismo origen sí lo comparten, por lo que un prefijo como "notes-app:settings" ayuda a distinguir las claves de varias aplicaciones.
Usa los métodos de almacenamiento
localStorage.setItem("notes-app:theme", "dark");
const theme = localStorage.getItem("notes-app:theme");
localStorage.removeItem("notes-app:theme");
setItem crea o sobrescribe una entrada. getItem devuelve su valor como cadena o null si está ausente. removeItem elimina una entrada. clear() elimina todas las entradas de esa área de almacenamiento para el origen, lo que puede afectar a otras funciones del mismo sitio. length y key(index) permiten inspeccionar las claves.
Usa estos métodos en lugar de asignaciones de propiedades como localStorage.theme = "dark". Las claves como "length" o "key" pueden entrar en conflicto con miembros integrados cuando se accede a ellas como propiedades.
Convierte los valores de forma explícita
Después de localStorage.setItem("count", 5), la lectura da "5". Sumar 1 directamente crea "51". Number(localStorage.getItem("count")) + 1 produce 6.
Un booleano almacenado presenta una trampa similar. setItem("darkMode", false) almacena "false", y una cadena no vacía es verdadera en contexto booleano. Lee con localStorage.getItem("darkMode") === "true" cuando esas sean las dos cadenas almacenadas esperadas.
Los objetos y arrays necesitan JSON:
localStorage.setItem("settings", JSON.stringify({
theme: "dark",
fontSize: 18,
}));
const settings = JSON.parse(localStorage.getItem("settings"))
?? { theme: "light", fontSize: 16 };
Sin serialización, un objeto normal se convierte en "[object Object]". JSON.parse(null) da null, por lo que el valor predeterminado cubre una entrada ausente. Una cadena almacenada mal formada sigue necesitando try/catch, y los datos analizados necesitan una comprobación de estructura antes de usarse.
Mantén pequeña la carga de trabajo
Las llamadas a Web Storage son síncronas: JavaScript espera cada una en el hilo principal. Úsalo para configuraciones, un borrador o una lista breve, no para grandes colecciones o archivos. IndexedDB proporciona almacenamiento asíncrono para datos estructurados más grandes.
Los navegadores actuales suelen permitir unos 5 MiB en cada área de Web Storage por origen. Un almacén lleno puede hacer que setItem lance QuotaExceededError; el acceso también puede fallar por la configuración de privacidad del navegador. Maneja el fallo sin impedir que el resto de la aplicación funcione. Las herramientas de desarrollo muestran los almacenes en la pestaña Application de Chrome y Edge o en la pestaña Storage de Firefox, donde eliminar entradas ayuda a probar las primeras visitas.
Puntos clave
- Elige
localStoragepara configuraciones compartidas persistentes ysessionStoragepara el estado de la sesión de una pestaña. - Las áreas de almacenamiento están separadas por origen.
getItemdevuelve una cadena onull.- Serializa objetos con JSON y restaura sus tipos al leerlos.
- Maneja los fallos de almacenamiento y mantén pequeñas las escrituras síncronas.
4.2 Restaura el estado y establece la caducidad de los datos en caché
Una aplicación suele cargar al iniciar y guardar al cambiar. Lee una lista guardada cuando se abre la página, renderízala y guarda la lista actualizada después de una edición. El almacenamiento del navegador es una copia práctica: puede faltar, estar dañada o desactualizada, o borrarse.
Valida antes de restaurar
Esta función de carga espera un array guardado de cadenas:
function loadTodos() {
try {
const value = JSON.parse(localStorage.getItem("todos"));
if (Array.isArray(value) && value.every(item => typeof item === "string")) {
return value;
}
} catch {
// Continue with an empty list if reading or parsing fails.
}
return [];
}
JSON.parse por sí solo no demuestra que el valor sea un array ni que sus elementos sean adecuados para la aplicación. Un JSON válido como 42 sigue teniendo la estructura incorrecta. Un valor con versión como { version: 2, todos: [...] } permite que el código más reciente reconozca formatos antiguos y los convierta o restaure un valor predeterminado.
Guarda la lista en memoria con localStorage.setItem("todos", JSON.stringify(todos)) después de cada cambio. Captura también los fallos de escritura; una página debería poder seguir funcionando aunque no pueda conservar el estado para la siguiente recarga. Un borrador de formulario que pertenece solo a una visita puede usar sessionStorage.
Añade una marca de tiempo a las respuestas en caché
localStorage.setItem("weather", JSON.stringify({
savedAt: Date.now(),
data,
}));
En una carga posterior, valida primero la estructura y la marca de tiempo del objeto en caché. Su antigüedad es Date.now() - savedAt. Úsalo solo mientras esa antigüedad sea menor que 10 * 60 * 1000, o 600 000 ms. Un valor guardado a las 10:00:00 tiene 450 000 ms de antigüedad a las 10:07:30 y se puede usar. A las 10:12:00, tiene 720 000 ms de antigüedad, así que obtén un valor actualizado. Con exactamente 600 000 ms, ha caducado según esta regla.
La caducidad es lógica de la aplicación: localStorage no elimina una entrada cuando termina tu intervalo de vigencia. Rechaza una marca de tiempo ausente o no válida en lugar de tratar una antigüedad desconocida como reciente. Puedes mantener visibles los datos obsoletos durante una actualización fallida si los identificas como antiguos.
Sincroniza otras pestañas
Cuando una pestaña modifica localStorage, las demás pestañas del mismo origen reciben un evento storage. La pestaña que escribe no recibe su propio evento. El evento expone key, oldValue, newValue y url.
window.addEventListener("storage", (event) => {
if (event.key === "theme") applyTheme(event.newValue);
});
Aplica también el tema inmediatamente en la pestaña que escribe. Maneja null cuando se elimina una clave. Un evento de almacenamiento no sustituye la actualización del estado de tu propia página.
Decide qué debe estar en otro lugar
No guardes contraseñas, números de tarjetas de pago ni claves secretas de API en Web Storage. Los scripts del origen pueden leerlo, incluidos el código de terceros y los scripts inyectados. Borra los datos personales pertinentes al cerrar sesión en dispositivos compartidos. Guarda el trabajo importante en un servidor o permite exportarlo, porque los usuarios pueden borrar los datos del sitio y las sesiones privadas los descartan.
Las cookies son distintas: las solicitudes correspondientes las envían al servidor, y los scripts de la página no pueden leer las cookies HttpOnly. Son pequeñas, de unos 4 KB cada una. Web Storage permanece en el navegador y los scripts pueden leerlo. IndexedDB es adecuado para datos estructurados más grandes mediante una API asíncrona.
Puntos clave
- Valida los datos analizados y recurre a una alternativa cuando falten o estén dañados.
- La vigencia de la caché depende de una marca de tiempo y de un límite de antigüedad definido por la aplicación.
- El evento
storagellega a otras pestañas del mismo origen, no a la que escribe. - Mantén los secretos y los datos irremplazables fuera de Web Storage.
5Usa las funciones de ubicación y portapapeles
Las API del navegador conectan una página con funciones como la ubicación y el portapapeles. Su disponibilidad depende del navegador, del contexto de seguridad de la página y de las decisiones del usuario. Detectarás una función antes de llamarla, pedirás permiso en un momento adecuado y manejarás tanto el éxito como la denegación. Una interacción completa incluye información visible y otra forma de terminar la tarea, como introducir una ciudad o copiar con el teclado el texto seleccionado.
5.1 Solicita una ubicación con una alternativa
La geolocalización es una API del navegador: una función proporcionada por el navegador, separada del lenguaje JavaScript. Como otras funciones del dispositivo, puede no estar disponible o ser denegada. Una página del tiempo debería seguir funcionando cuando un lector decide escribir una ciudad.
Comprueba la función y el contexto
Detecta la propia función con "geolocation" in navigator. Comprobar el nombre del navegador es menos fiable: las versiones y la configuración cambian lo que está disponible. La geolocalización necesita un contexto seguro, normalmente HTTPS; http://localhost también cumple el requisito para el desarrollo. window.isSecureContext indica si la página actual lo cumple. HTTP sin cifrar en la dirección de red de otro dispositivo no es lo mismo que localhost.
Explica por qué es útil la ubicación y solicítala cuando el lector haga clic en «Usar mi ubicación». El navegador gestiona la solicitud de permiso. Una persona puede permitirla o bloquearla, y una denegación anterior puede hacer que una llamada posterior falle sin otra solicitud. El usuario puede cambiar esa decisión en la configuración del sitio.
Lee el resultado de la función de devolución de llamada
navigator.geolocation.getCurrentPosition(success, error, options) usa funciones de devolución de llamada. Si tiene éxito, position.coords contiene la latitud y la longitud en grados decimales y accuracy en metros. La precisión es un radio estimado de incertidumbre, no una precisión decimal adicional. Si falla, el código 1 significa permiso denegado, 2 significa posición no disponible y 3 significa tiempo límite agotado.
Las opciones controlan el intento:
enableHighAccuracy: solicita mayor precisión; valor predeterminadofalse.timeout: límite de espera en milisegundos; valor predeterminadoInfinity.maximumAge: antigüedad máxima de una posición aceptable almacenada en caché; valor predeterminado0.
Usa un tiempo límite finito para que la página pueda dejar de esperar. watchPosition observa las actualizaciones a lo largo del tiempo y devuelve un ID; pasa ese ID a clearWatch cuando deba detenerse el seguimiento.
Envuelve las funciones de devolución de llamada al usar await
function getPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, options);
});
}
async function useLocation() {
if (!("geolocation" in navigator)) {
showCityInput();
return;
}
try {
const { coords } = await getPosition({ timeout: 10000 });
const url = new URL("https://api.example.com/weather");
url.searchParams.set("lat", coords.latitude.toFixed(2));
url.searchParams.set("lon", coords.longitude.toFixed(2));
await loadWeather(url);
} catch {
showCityInput();
}
}
Aquí showCityInput muestra el control de entrada manual y loadWeather solicita y renderiza el tiempo. Conecta useLocation al botón de ubicación. El bloque catch cubre el fallo de ubicación y la solicitud meteorológica; en ambos casos, la entrada manual sigue disponible.
Solicita solo la precisión útil
Una posición de latitud 52.3676, longitud 4.9041 y precisión 35 tiene un radio estimado de unos 35 m. Redondear a 52.37 y 4.90 reduce la precisión enviada al servicio meteorológico. Un intervalo de latitud de 0,01° equivale aproximadamente a 1,1 km; la separación de longitud varía con la latitud. Esa precisión regional es adecuada para una previsión sin compartir las coordenadas más detalladas.
Donde esté disponible la API de permisos, navigator.permissions.query({ name: "geolocation" }) informa de "granted", "denied" o "prompt". Detecta y maneja también esa API. Su estado ayuda a adaptar la interfaz, pero no sustituye el manejo de errores de la llamada de ubicación.
Puntos clave
- Detecta la geolocalización y usa un contexto seguro.
- Solicita la ubicación después de una acción clara del usuario y explicando el propósito.
- La latitud y la longitud usan grados; la precisión usa metros.
- Establece un tiempo límite finito y ofrece entrada manual si hay un fallo.
- Envía solo la precisión de ubicación que necesita la función.
- El estado del permiso no garantiza una posición utilizable.
5.2 Copia texto y aprende otra API del navegador
La API del portapapeles permite que una página copie texto sin pedir al lector que lo seleccione primero. Como la geolocalización, necesita comprobaciones de disponibilidad, una acción adecuada del usuario, manejo de errores y una alternativa.
Copia durante el clic
navigator.clipboard.writeText(text) devuelve una promesa. Espérala antes de informar del éxito. Se requiere un contexto seguro y una operación denegada puede rechazarse con NotAllowedError. Llámalo directamente desde un manejador de clic: Firefox y Safari requieren una interacción reciente del usuario, mientras que los requisitos de Chromium también pueden depender del permiso de escritura en el portapapeles.
copyButton.addEventListener("click", async () => {
try {
if (!navigator.clipboard?.writeText) {
throw new Error("Copy unavailable");
}
await navigator.clipboard.writeText(codeField.value);
copyButton.textContent = "Copied!";
} catch {
codeField.focus();
codeField.select();
copyButton.textContent = "Copy selected text: Ctrl+C / Cmd+C";
}
setTimeout(() => {
copyButton.textContent = "Copy";
}, 2000);
});
codeField es una entrada de texto o un área de texto y copyButton es el botón de la página. Si falla la copia, seleccionar el texto ofrece una opción con el teclado: Ctrl+C en muchos sistemas o Cmd+C en macOS. La etiqueta vuelve a ser «Copy» después de 2000 ms. Nunca muestres «Copied!» antes de que se cumpla la promesa.
La lectura usa navigator.clipboard.readText() y tiene controles más estrictos porque un portapapeles puede contener material privado de otras aplicaciones. Un navegador puede requerir permiso o mostrar una solicitud de pegado. El permiso para escribir no implica permiso para leer.
Trata la conectividad como una pista
navigator.onLine y los eventos online y offline de la ventana ayudan a mostrar un aviso de conexión. No indican con certeza si tu API es accesible. Un dispositivo puede tener conexión de red mientras el servidor de la API está caído o es inaccesible.
window.addEventListener("offline", () => {
status.textContent = "You are offline.";
});
Sigue manejando los errores alrededor de fetch incluso cuando navigator.onLine sea verdadero. Usa una región activa adecuada para el mensaje de estado.
Lee una búsqueda que se pueda compartir
La API URL lee la cadena de consulta de la propia página, además de construir URL de API. En https://books.example.org/search?q=dune, new URL(location.href).searchParams.get("q") devuelve "dune". Lee ese valor al cargar la página para restaurar una búsqueda desde un enlace compartido. Un parámetro ausente devuelve null, así que decide qué debe mostrar entonces la pantalla inicial.
Usa un método de aprendizaje
Para otra API del navegador, lee su sintaxis, sus reglas de contexto seguro y permisos, su tabla de compatibilidad y su estado Baseline en MDN. Después detecta la función, llámala desde una acción del usuario cuando sea necesario, maneja su promesa o sus funciones de devolución de llamada y ofrece una alternativa cuando falte o se deniegue.
La API de notificaciones muestra notificaciones del sistema después de obtener permiso; Web Share abre un menú para compartir del dispositivo donde es compatible; Canvas dibuja gráficos; las API multimedia controlan el audio y el vídeo. Una API de mapas de terceros puede añadir una biblioteca y una clave del proveedor. Sus credenciales siguen las mismas reglas de claves secretas que las de cualquier otro servicio. Probar un navegador en localhost no demuestra que otro dispositivo o navegador tenga la misma compatibilidad y el mismo contexto.
Puntos clave
- Espera a
writeTextantes de informar de que la copia tuvo éxito. - Conserva una alternativa para copiar con el teclado cuando falle el acceso al portapapeles.
- La lectura del portapapeles tiene reglas de permiso distintas y más estrictas.
- El estado de conexión no demuestra que la API sea accesible.
- Usa parámetros de URL para restaurar una búsqueda que se pueda compartir.
- Comprueba la compatibilidad, detecta funciones y maneja las denegaciones para cada API del navegador.
Ejemplos de Fetch y API del navegador
1Construye y actualiza una lista de lectura
14 pasos
- 1IntroducciónSigue un intercambio
Una página de lista de lectura necesita cargar libros y añadir una nota sobre uno de ellos. La página es el cliente; la API es el servidor. Cada intercambio tiene una solicitud que describe la acción y una respuesta que describe su resultado.
Primero interpretaremos el intercambio, después conectaremos los dos pasos asíncronos de la carga de JSON y, por último, enviaremos un cambio. La respuesta del servidor determina qué puede mostrar la página de forma segura a continuación.
- 2EjemploInterpreta el recurso y los filtros
La página envía
GET https://api.example.com/books?author=Le%20Guin&limit=5.GETsolicita una lectura./booksidentifica el recurso. La consulta filtra por autor y limita el número de resultados.%20representa el espacio en «Le Guin». La documentación de la API determina estos nombres de parámetros; la página no puede elegir un nombre distinto y esperar que el servicio lo entienda. - 3Idea claveDistingue el estado de la conexión
Una respuesta puede indicar
200 OKcon un libro o404 Not Foundcon un error. Ambas demuestran que un servidor respondió. Un fallo de conexión no proporciona ningún estado HTTP a la página.Inspecciona la pestaña Network para ver la URL completa, el método, el estado, las cabeceras y el cuerpo. Si la API devolvió el JSON esperado, el siguiente lugar que debes inspeccionar es el código que lo lee o muestra.
- 4DesafíoElige un método para un cambio
Ya existe una nota. La página debe modificar solo su campo
doney conservar su texto. ¿Qué método HTTP corresponde a esa operación y por qué sería incorrecto usarGET?---reveal---
Usa
PATCHpara la actualización parcial.GETes un método de lectura seguro y no debe usarse para solicitar un cambio de datos.PUTdescribiría una sustitución completa y podría restablecer los campos omitidos del cuerpo. - 5ExplicaciónEspera la respuesta
Empieza con
const response = await fetch(url). Esto espera hasta que llegan las cabeceras de la respuesta y proporciona unResponse, no los libros analizados.La respuesta aún puede ser un error HTTP.
fetchse cumple para un404porque existe una respuesta. Compruebaresponse.okantes de considerar que la operación tuvo éxito; es verdadero para los códigos de estado de200a299. - 6EjemploComprueba y lee el cuerpo
Continúa dentro de la función asíncrona:
if (!response.ok) { throw new Error(`HTTP error ${response.status}`); } const data = await response.json();La segunda espera lee y analiza el cuerpo. Ahora
dataes un valor de JavaScript. Untry/catchexterior puede manejar tanto el error de estado lanzado aquí como los fallos al obtener o analizar el cuerpo. - 7EjemploEncuentra el array anidado
Supongamos que el cuerpo es
{"results":[{"title":"Dune"}],"total":1}.El primer paso,
data.results, accede al array.[0]accede a su primer objeto..titleda"Dune". Una función de renderizado debe recibirdata.results, no todo el objeto exterior. La vista previa de la respuesta en Network es útil cuando la estructura de la API difiere de lo que esperaba la página. - 8DesafíoDiagnostica el valor ausente
El código usa
const data = response.json()y después intenta acceder adata.results[0]. El cuerpo sí es JSON válido con un arrayresults. ¿Qué falta?---reveal---
Espera el cuerpo:
const data = await response.json(). Sin esa espera,dataes una promesa y no tiene una propiedadresults. El primerawait fetch(...)no esperó también el análisis de JSON. - 9ConsejoConserva los signos en una búsqueda
Construye los parámetros de consulta mediante la API URL:
const url = new URL("https://api.example.com/search"); url.searchParams.set("q", "rock & roll");El valor se convierte en
rock+%26+roll. El signo & permanece dentro de la frase de búsqueda en lugar de dividir la consulta. Reutiliza la respuesta analizada después de cargarla: llamar a un segundo lector de cuerpo sobre la misma respuesta falla porque el cuerpo ya se consumió. - 10EjemploPrepara un envío JSON
Para crear una nota, serializa los campos e indica su formato:
const response = await fetch("https://api.example.com/notes", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title: "Read", done: false }), });El método solicita la creación, la cabecera declara JSON y el cuerpo contiene texto JSON en lugar de un objeto normal.
- 11ConexiónUsa el registro almacenado
El servidor puede devolver
201 Createdcon{"id":31,"title":"Read","done":false}. Añade ese registro devuelto al estado de la página. Su ID permite que una acción posterior llame a/notes/31.Para un formulario con archivos, pasa
FormDataen lugar de JSON y deja que el navegador establezca su delimitador multiparte. Una solicitudGETno puede llevar un cuerpo mediantefetch; los campos de búsqueda van en la cadena de consulta. - 12DesafíoManeja un éxito sin cuerpo
Al eliminar una nota guardada se devuelve
204. El código compruebaresponse.ok, después llama aresponse.json()y muestra un error. ¿Falló necesariamente la eliminación y qué debería cambiar?---reveal---
No:
204indica que la operación terminó correctamente sin cuerpo. Omite el análisis de JSON para ese estado y actualiza la página después de comprobarlo. El fallo de análisis se debió a intentar leer contenido vacío, no a una prueba de que fallara la eliminación. - 13DesafíoRevisa un flujo de envío completo
Se puede hacer clic dos veces en un botón de guardar mientras se ejecuta un
POST. Una respuesta correcta proporciona un ID nuevo. Indica los dos comportamientos de la página que evitan un duplicado accidental y conservan ese ID.---reveal---
Desactiva el botón durante la solicitud y restablécelo en
finally. Si tiene éxito, actualiza a partir del registro devuelto, incluido su ID. El botón evita clics repetidos; el resultado del servidor proporciona valores que no existían en los datos enviados. - 14RepasoComprueba el intercambio en cada paso
Cuando una solicitud no funcione como esperas, inspecciona la operación en orden: la URL y el método documentados, el estado real, el lector de cuerpo elegido y la estructura de los datos entregados a la página.
Para una escritura, comprueba también el tipo de contenido y el cuerpo serializado. Un éxito sin contenido no necesita un lector JSON. Una respuesta de creación debe proporcionar el registro guardado que se usará para la siguiente edición o eliminación.
2Construye una página de búsqueda que se mantenga actualizada
18 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónMantén la pantalla vinculada a la búsqueda
- 2EjemploSustituye la lista anterior
- 3Idea claveDistingue el cero de los datos ausentes
- 4DesafíoManeja el texto y los enlaces externos
- 5EjemploIdentifica la unidad de tiempo
- 6ExplicaciónElige la zona de presentación
- 7EjemploDa formato a las unidades fraccionarias documentadas
- 8DesafíoSepara la configuración regional del valor
- 9ExplicaciónEmpieza con una espera visible
- 10EjemploTermina todas las rutas
- 11DesafíoReconoce una búsqueda correcta sin resultados
- 12ConsejoEspera antes de un reintento temporal
- 13EjemploObserva el orden de finalización
- 14EjemploCancela una solicitud obsoleta
- 15ConexiónReduce las llamadas mientras se escribe
- 16DesafíoElige el éxito parcial
- 17DesafíoProtege toda la interacción actual
- 18RepasoPrueba la interfaz con respuestas imperfectas
3Diagnostica una llamada a una API de otro origen
10 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónSepara dos cuestiones de permisos
- 2EjemploCompara los orígenes completos
- 3ExplicaciónInterpreta el permiso del servidor
- 4EjemploSigue primero la verificación previa
- 5DesafíoExplica un éxito solo en la terminal
- 6EjemploEncuentra la clave expuesta
- 7ConexiónTraslada el límite del secreto
- 8DesafíoDistingue el transporte del secreto
- 9DesafíoComprueba las cookies y las respuestas legibles
- 10RepasoDiagnostica el límite que falló
4Restaura una lista guardada sin romper la página
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónConserva una copia local práctica
- 2ExplicaciónElige qué debe conservarse
- 3EjemploConserva un array como texto
- 4DesafíoRestaura el tipo previsto
- 5ConsejoManeja una escritura que supera la capacidad
- 6EjemploComprueba más que la sintaxis JSON
- 7EjemploAñade una hora a la caché
- 8DesafíoCalcula qué caché está vigente
- 9ConexiónSigue un tema entre pestañas
- 10Idea claveProtege los datos importantes
- 11DesafíoRecupérate de un formato guardado antiguo
- 12RepasoPrueba una primera visita y una visita posterior
5Añade botones útiles de ubicación y copia
13 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónHaz que la acción sea comprensible
- 2ExplicaciónComprueba el contexto y la función
- 3ConsejoSolicita el permiso cuando la función sea útil
- 4EjemploEstablece una espera finita
- 5EjemploLee solo la precisión útil
- 6DesafíoRecupérate de una denegación
- 7EjemploEscribe durante el clic
- 8Idea claveEspera antes de confirmar la copia
- 9DesafíoTrata una señal de conexión como una pista
- 10ConexiónRestaura una búsqueda desde su enlace
- 11ConsejoComprueba otra función del navegador
- 12DesafíoRevisa ambos botones juntos
- 13RepasoPrueba también las decisiones de la persona
Ejercicios de Fetch y API del navegador
Set 1: Solicitudes, resultados y funciones del navegador10 Preguntas de Práctica
Pregunta 1 de 10
403. ¿Qué indica ese estado a la página?Mostrar respuestaOcultar respuesta
403 significa que el servidor entendió la solicitud y se niega a cumplirla. No demuestra que el usuario haya proporcionado credenciales válidas ni que iniciar sesión vaya a resolver la denegación. Un fallo de conexión de red no proporcionaría un estado HTTP que la página pudiera leer.Pregunta 2 de 10
200 con {"items":[{"name":"Cedar"}]}. ¿Qué asignación almacena el nombre del primer elemento después de const response = await fetch(url)?Mostrar respuestaOcultar respuesta
json() lea y analice el cuerpo y después sigue la propiedad exterior items hasta el primer objeto del array. Llamar a json() sin await deja una promesa que no tiene un array items. Leer con text() da una cadena, no el objeto analizado necesario para acceder a la propiedad.Pregunta 3 de 10
body al enviar { label: "Read" }?Mostrar respuestaOcultar respuesta
JSON.stringify convierte el objeto en texto JSON válido para el cuerpo de la solicitud. Convertir un objeto normal con String o toString() produce "[object Object]", que el punto de acceso JSON no puede analizar. La solicitud también necesita el método documentado y una cabecera de tipo de contenido JSON.Pregunta 4 de 10
{ remaining: 0, owner: null }. ¿Cómo puede la página mostrar el recuento restante y usar "Unknown" para el nombre de propietario ausente?Mostrar respuestaOcultar respuesta
name de null. Usar || para el recuento sustituye el cero porque es falso en contexto booleano. Una alternativa después de data.owner.name no puede ayudar cuando el acceso a name ya ha lanzado un error.Pregunta 5 de 10
amount: 3785, currency: "USD" como unidades fraccionarias enteras. ¿Qué número debe recibir el formateador de moneda?Mostrar respuestaOcultar respuesta
3785 directamente mostraría un importe 100 veces mayor. Intl.NumberFormat da formato al número que recibe; no deduce que un importe de API esté en centavos.Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
finally se ejecuta después del trabajo protegido tanto si tiene éxito como si lanza un error, por lo que es el lugar adecuado para el restablecimiento necesario en ambas rutas. Ponerlo solo en catch omite el éxito; dejarlo después del renderizado omite el fallo. Un temporizador restablecería los controles sin saber si la solicitud terminó.Pregunta 7 de 10
https://studio.example.org/edit. ¿Cuál es el origen de esa página?Mostrar respuestaOcultar respuesta
/edit identifica un recurso dentro del origen y no forma parte del origen. Cambiar el esquema a HTTP crearía un origen distinto incluso con el mismo host.Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Pregunta 9 de 10
localStorage.setItem("visits", 8), ¿cuál es el valor de localStorage.getItem("visits") + 1?Mostrar respuestaOcultar respuesta
"8", por lo que + 1 concatena cadenas y da "81". No restaura el tipo numérico que se pasó a setItem. Convierte la cadena almacenada con Number antes de sumar si el resultado previsto es el número 9.Pregunta 10 de 10
1. ¿Qué respuesta dirigida al usuario corresponde al fallo?Mostrar respuestaOcultar respuesta
1 significa que se denegó el permiso, por lo que debes ofrecer otra forma de introducir la ubicación. El tiempo límite agotado es el código 3 y no explica este fallo. Las solicitudes repetidas no pueden forzar el permiso; una denegación recordada puede requerir que el usuario cambie la configuración del sitio en el navegador.Set 2: Sigue los datos por la interfaz10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
fetch devuelve un Response con estado 502. El código tiene un manejador catch, pero nunca comprueba response.ok. ¿Por qué podría no aparecer nunca su mensaje de error HTTP?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
204 cuando tiene éxito. ¿Qué debe hacer la página antes de intentar analizar JSON?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
Promise.all?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
POST JSON con Content-Type: application/json. No hay ningún permiso de verificación previa en caché. ¿Qué debe comprobar el navegador antes de enviar ese POST?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
http://localhost, pero su función de ubicación no aparece cuando se abre en un teléfono mediante una dirección de red HTTP. La aplicación también deja de funcionar cuando los usuarios de escritorio deniegan la ubicación. ¿Qué diseño resuelve ambos fallos?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
navigator.clipboard.writeText(text). ¿En qué momento debe mostrar «¡Copiado!»?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Depura solicitudes, almacenamiento y permisos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
PUT /profiles/29 como sustitución del perfil. ¿Qué implica la idempotencia cuando se envía dos veces la misma solicitud completa?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
new Date y muestra enero de 1970. ¿Qué conversión debe preceder al formato de la fecha?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
503 con Retry-After: 12. ¿Qué comportamiento comunica el estado y facilita la recuperación?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
if (localStorage.getItem("compact")). El texto almacenado es "false", pero el modo compacto se activa. ¿Por qué?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
-12.0464, longitud -77.0428 y precisión 80. ¿Qué describe 80?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
https://recipes.example.org/search?q=green+tea lee new URL(location.href).searchParams.get("q"). ¿Qué valor obtiene?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Diseña funciones de API fiables10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
429. ¿Qué significa ese estado?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
<b>, un enlace javascript: y remaining: 0. La página debe mostrar el título literal, permitir solo enlaces web normales y conservar el recuento. ¿Qué plan de renderizado cumple las tres necesidades?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
Intl.DateTimeFormat usando una configuración regional fija en-US, pero sin la opción timeZone. Las horas mostradas son distintas. ¿Qué explica la diferencia?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
PATCH JSON a otro origen usa credentials: "include". La verificación previa lo permite. La respuesta final tiene un comodín para el origen permitido y admite credenciales, por lo que JavaScript no puede leerla. El servidor también supone que CORS hace innecesarias las comprobaciones del usuario. ¿Qué política de respuesta y acceso corrige este diseño?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
.map. Algunos usuarios tienen el JSON válido {"version":1,"items":[]} dejado por código antiguo y otros tienen texto dañado. ¿Qué plan de restauración maneja ambos casos?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
navigator.onLine === true, pero una llamada a una API se rechaza. ¿Qué debe deducir la página sobre la conectividad y qué debe manejar después?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Activación del usuario
Agrupación de llamadas tras un periodo de inactividad
Almacenamiento de sesión (sessionStorage)
Almacenamiento local (localStorage)
Almacenamiento web (Web Storage)
Alternativa de respaldo
API del portapapeles
API web
Atributo HttpOnly
C
Cabecera HTTP
Content-Type indica al programa receptor que el cuerpo adjunto contiene JSON.Cabecera Retry-After
15 de Retry-After pide a la página que espere quince segundos antes de otra solicitud.Caché
Caducidad
Clave de API
Coalescencia nula
?? solo cuando el valor de su izquierda es null o undefined, y conserva los ceros válidos.Codificación de URL
Código de estado
201 indica a la página que el servidor creó un recurso en respuesta a la solicitud.Condición de carrera
Configuración regional
en-US escribe una fecha de forma distinta a en-GB aunque ambas den formato al mismo instante.Contenido mixto
Contexto seguro
Controlador de cancelación (AbortController)
Cuerpo de la respuesta
Cuerpo de la solicitud
Cuota de almacenamiento
D
Datos de formulario (FormData)
Delimitador de contenido multiparte
Detección de funcionalidades
"geolocation" in navigator determina si la página puede ofrecer la ubicación del dispositivo.E
Encadenamiento opcional
?. es null o undefined y devuelve undefined.book.author?.name maneje un libro cuyo objeto de autor falta en la respuesta.Error de análisis sintáctico
204 vacío causa un error de análisis de JSON aunque el servidor haya completado correctamente la operación.Espera exponencial entre reintentos
Estado de carga
Estado sin datos
Evento de almacenamiento
F
Formateador Intl.NumberFormat
Intl.NumberFormat para cada precio en lugar de volver a construir una cadena monetaria para cada elemento.G
Geolocalización
I
Idempotencia
IndexedDB
Indicador de compatibilidad Baseline
Intercambio de recursos entre orígenes (CORS)
J
JSON
results antes de construir los elementos de lista.L
Límite de frecuencia de solicitudes
M
Marca de tiempo Unix
Método Promise.all
Método Promise.allSettled
O
Objeto Response
200, pero la página aún espera json() para obtener los datos del libro.Operación síncrona
Origen
P
Paginación
Parámetro de consulta
?, que un punto de acceso usa para entradas como búsquedas o límites de página.limit=12 pide al punto de acceso de búsqueda que devuelva como máximo doce resultados.Permiso
Política del mismo origen
Precisión de la ubicación
Propiedad textContent
textContent muestra sus corchetes angulares literalmente en lugar de crear un elemento HTML.Punto de acceso de la API
POST para crear una nota y devuelve el identificador del nuevo registro.R
Región activa
role="status" anuncia «Cargando…» y el mensaje posterior con los resultados de búsqueda.Renderizado
Respuesta HTTP
404 y explica en su cuerpo que no se encontró el libro solicitado.Respuesta opaca
S
Secuencias de comandos entre sitios (XSS)
textContent para los títulos de una API elimina la interpretación como HTML que puede permitir secuencias de comandos entre sitios.Señal de cancelación (AbortSignal)
AbortSignal.timeout(4000) limita una solicitud a cuatro segundos de tiempo activo.Serialización
JSON.stringify conserva los campos de una nota cuando se envían como cuerpo JSON de una solicitud.Solicitud de verificación previa
Solicitud HTTP
/books e incluye un parámetro de consulta que limita el número de resultados.T
Tiempo universal coordinado (UTC)
Z al final de una fecha y hora ISO.Token de acceso
U
Unidad monetaria fraccionaria
4680 representa 46.80 dólares.Z
Zona horaria
Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.