JavaScript ES7
JavaScript 7, ECMAScript (ES7 o ES2016) es el estándar que sigue JavaScript que se lanzó en el 2016.
Principales novedades de ES7
Spread or Rest Operator (...)
Promesas (Promise)
Una promesa en JavaScript es similar a una promesa en la vida real. Cuando hacemos una promesa en la vida real, es una garantía de que vamos a hacer algo en el futuro. Porque las promesas solo se pueden hacer para el futuro.
Cuando definimos una promesa en JavaScript, se resolverá cuando llegue el momento, o será rechazada.
Una Promesa es un objeto. Hay 3 estados del objeto Promesa:
- Pendiente: estado inicial, antes de que la promesa tenga éxito o falle.
- Resuelto: promesa completada.
- Rechazado: promesa fallida.
Observaciones
- Cuando solicitamos datos del servidor mediante una Promesa, estará en modo pendiente hasta que recibamos nuestros datos. Si logramos obtener la información del servidor, la Promesa se resolverá con éxito. Pero si no obtenemos la información, entonces la Promesa estará en el estado rechazado.
Recursos
- MDN Web ES
Creación
Se crea un promesa con dos parámetros, uno para el éxito (resolve) y otro para el error (reject). Finalmente habrá una condición. Si se cumple la condición, la promesa se resolverá, de los contrario será rechazada.
const miPromesa = new Promise((resolve, reject) => { let condition; if(condicion) { resolve('La promesa se resuelve con éxito!!!'); } else { reject('La promesa es rechazada!!!'); } });
Uso
then
Si la Promesa se resuelve (caso de éxito), algo sucederá después (depende de lo que hagamos con la promesa exitosa).
miPromesa.then();
Se llama al método then() después de que se resuelva la promesa . Entonces podemos decidir qué hacer con la Promesa resuelta.
Ejemplo
Registremos el mensaje en la consola lo que obtuvimos de la promesa:
miPromesa.then((message) => { console.log(message); });
catch
Si la Promesa falla, entonces, necesitamos usar el método catch(). Del mismo modo que utilizamos el método then(). También podemos utilizar el método catch() justo después de then().
Ejemplo
miPromesa.then((message) => { console.log(message); }).catch((message) => { console.log(message); });
Entonces si la promesa es rechazada, saltará al método catch() y esta vez veremos un mensaje diferente en la consola.
Fetch API
El API fetch es un nuevo estándar que viene a dar una alternativa para interactuar por HTTP, con un diseño moderno, basado en promesas, con mayor flexibilidad y capacidad de control a la hora de realizar llamadas al servidor.
El API Fetch está soportado de forma nativa por Edge 14, Firefox 39, Chrome 42 y Opera 29. Para Internet Explorer 10 o Safari 6.1 o superiores o versiones anteriores de Firefox o Chrome, podemos utilizar el polyfill publicado por Github https://github.com/github/fetch.
Recursos
- MDN Web EN
Partes importantes
Funcionamiento básico
Una de las características más importantes del API fetch es que utiliza promesas, es decir, devuelve un objeto con dos métodos, uno then() y otro catch() a la que pasaremos una función que será invocada cuando se obtenga la respuesta o se produzca un error.
Aquí hay que aclarar un punto con los errores: si se devuelve un código HTTP correspondiente a un error no se ejecutará el catch(), ya que se ha obtenido una respuesta válida, por lo que se ejecutará el then(). Sólo si hay un error de red o de otro tipo se ejecutará el catch().
Otro aspecto importante que hay que comprender es que para obtener el body o cuerpo del mensaje devuelto por el servidor deberemos obtener una segunda promesa por medio de los métodos del objeto Response. Por ello será muy habitual ver dos promesas encadenadas, una para el fetch() y otra con el retorno del método que utilicemos para obtener el body.
Ejemplo API fetch básico
fetch('https://httpbin.org/ip') .then(function(response) { return response.text(); }) .then(function(data) { console.log('data = ', data); }) .catch(function(err) { console.error(err); });
Observaciones:
- Hemos llamado a fetch() con la URL a la que queremos acceder como parámetro.
- Esta llamada nos devuelve una promesa.
- El método then() de esa promesa nos entrega un objeto response.
- Del objeto response llamamos al método text() para obtener el cuerpo retornado en forma de texto.
- Nos devuelve otra promesa que se resolverá cuando se haya obtenido el contenido.
- El método then() de esa promesa recibe el cuerpo devuelto por el servidor en formato de texto.
- Hemos incluido un catch() por si se produce algún error.
Opciones de fetch()
En el ejemplo anterior no hemos indicado que método teníamos que utilizar, simplemente hemos pasado la URL y se considera que queremos utilizar el método GET que es el valor por defecto. La forma de configurar esta llamada es utilizar el segundo parámetro de fetch(), donde pasaremos un objeto con las opciones.
Ejemplo:
fetch('https://httpbin.org/post', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'a=1&b=2' }) .then(function(response) { console.log('response =', response); return response.json(); }) .then(function(data) { console.log('data = ', data); }) .catch(function(err) { console.error(err); });
Response
En la función que pasamos a then() vamos a recibir un objeto Response. Este objeto contiene la respuesta que hace el servidor y dispone de una serie de propiedades con los valores de esa respuesta.
Ejemplo response.json()
fetch('https://httpbin.org/ip') .then(function(response) { console.log('response.body =', response.body); console.log('response.bodyUsed =', response.bodyUsed); console.log('response.headers =', response.headers); console.log('response.ok =', response.ok); console.log('response.status =', response.status); console.log('response.statusText =', response.statusText); console.log('response.type =', response.type); console.log('response.url =', response.url); return response.json(); }) .then(function(data) { console.log('data = ', data); }) .catch(function(err) { console.error(err); });
Observaciones: El contenido del body no está disponible directamente en este objeto Response y tenemos que llamar uno de los métodos disponibles para que nos devuelva una promesa donde recibiremos el valor enviado por el servidor. Los métodos disponibles son:
- response.text() para que nos devuelve el contenido en formato texto.
- response.json() para que lo devuelva como objeto Javascript.
- response.arrayBuffer() para obtenerlo como ArrayBuffer.
- response.blob() como valor que podemos manejar con URL.createObjectURL().
- response.formData() para obtenerlos como FormData.
Una característica que tenemos que tener en cuenta es que solo podemos hacer una obtención de body, tras la cual ya no podemos volver solicitar otra conversión. Para resolver esta situación el objeto Response tiene el método clone() que nos permite duplicar el objeto y hacer múltiples gestiones de body.
Request
Una forma alternativa de configurar el comportamiento de fetch() es crear un objeto Request y pasar este objeto como parámetro a fetch(). El constructor de Request recibe dos parámetros: la URL y el objeto con las opciones.
Ejemplo objeto Request:
let request = new Request('https://httpbin.org/get', { method: 'GET', mode: 'cors', credentials: 'omit', cache: 'only-if-cached', referrerPolicy: 'no-referrer' }); console.log('request =', request); fetch(request) .then(function(response) { console.log('response =', response); return response.text(); }) .then(function(data) { console.log('data = ', data); }) .catch(function(err) { console.error(err); });
Observaciones: Este objeto Response puede ser de utilidad si tenemos que hacer varias llamadas con los mismos valores, ya que podemos reutilizarlo tantas veces como nos haga falta. Acepta todas las configuraciones que vimos en fetch().
Headers
Aunque podemos incluir las cabeceras por medio del objeto Request o como parte del objeto que se pasa como segundo parámetro a fetch(), tenemos a nuestra disposición el objeto Headers que nos ayuda a gestionar las cabeceras de una forma más precisa.
Ejemplo Header():
let headers = new Headers(); headers.append('a', '1'); headers.append('b', '2'); let request = new Request('https://httpbin.org/get', { headers: headers }); console.log('request =', request); for (var k of request.headers.keys()) { console.log('request.headers.get("' + k + '") =', request.headers.get(k)); } fetch(request) .then(function(response) { console.log('response =', response); for (var k of response.headers.keys()) { console.log('response.headers.get("' + k + '") =', response.headers.get(k)); } return response.text(); }) .then(function(data) { console.log('data = ', data); }) .catch(function(err) { console.error(err); });
Observaciones: El objeto Headers se puede asignar a Request, pero también está presente en Response con las cabeceras que nos devuelve el servidor. Si queremos consultar las cabeceras devueltas tenemos que utilizar los métodos que ofrece Headers:
- Headers.append(key, value): añade un valor a una cabecerá ya existe o crea una nueva cabecera si no existe.
- Headers.delete(key): borra una cabecera.
- Headers.entries(): retorna un iterador con todas las parejas clave/valor.
- Headers.get(key): devuelve el primer valor de una cabecera.
- Headers.getAll(key): devuelve una matriz con todos los valores de una cabecera.
- Headers.has(key): comprueba si una cabecera existe.
- Headers.keys(): devuelve un interador con todas las claves.
- Headers.set(key, value): añade una cabecera nueva.
- Headers.values(): devuelve un iterador con todos los valores.
FormData
API fetch se apoya en otros API estandarizados como el API FormData, para poder construir de una forma más completa el body con el contenido de un formulario.
Este API se puede utilizar de dos formas, una es pasando un objeto form del DOM al constructor de FormData, por ejemplo: new FormData(document.getElementById('myForm'), la otra creando un objeto con new FormData() e ir incluyendo los valores uno a uno por medio de los métodos append() o set().
Ejemplo FormData():
let dataSend = new FormData(); dataSend.append('a', '1'); dataSend.append('b', '2'); let request = new Request('https://httpbin.org/put', { method: 'PUT', body: dataSend }); console.log('request =', request); for (var k of dataSend.keys()) { console.log('dataSend.get("' + k + '") =', dataSend.get(k)); } fetch(request) .then(function(response) { console.log('response =', response); return response.text(); }) .then(function(data) { console.log('data = ', data); }) .catch(function(err) { console.error(err); });
Observaciones:
- No ha sido necesario incluir una cabecera Content-Type, ya que se añade directamente al asociar body a un objeto FormData.