Promise

Baseline Widely available *

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

* Some parts of this feature may have varying levels of support.

El objeto Promise representa la eventual finalización (o falla) de una operación asincrónica y su valor resultante.

Nota: Esta característica está disponible en Web Workers.

Para conocer cómo funcionan las promesas y cómo puede usarlas, le recomendamos que lea primero Usando promesas.

Descripción

Una Promesa (Promise) es un proxy de un valor que no necesariamente se conoce cuando se crea la promesa. Le permite asociar controladores con el valor eventual de éxito o el motivo de falla de una acción asíncrona. Esto permite que los métodos asíncronos devuelvan valores como los métodos síncronos: en lugar de devolver inmediatamente el valor final, el método asíncrono devuelve la promesa de proporcionar el valor en algún momento en el futuro.

Un Promise está en uno de estos estados:

  • pending (pendiente): estado inicial, ni cumplido ni rechazado.
  • fulfilled (cumplida): lo que significa que la operación se completó con éxito.
  • rejected (rechazada): lo que significa que la operación falló.

Una promesa pendiente puede cumplirse con un valor o rechazarse con un motivo (error). Cuando ocurre cualquiera de estas opciones, se llama a los controladores asociados en cola por el método then de una promesa. Si la promesa ya se ha cumplido o rechazado cuando se adjunta un manejador correspondiente, se llamará al manejador, por lo que no existe una condición de carrera entre la finalización de una operación asíncrona y la conexión de sus manejadores.

Como los métodos Promise.prototype.then() y Promise.prototype.catch() devuelven promesas, se pueden encadenar.

Nota: Varios otros lenguajes tienen mecanismos para la evaluación diferida y el aplazamiento de un cálculo, a los que también llaman "promesas", p.ej. Scheme. Las promesas en JavaScript representan procesos que ya están sucediendo, que se pueden encadenar con funciones de devolución de llamada. Si está buscando evaluar lentamente una expresión, considere usar una función sin argumentos, p.ej. f = () => expression para crear la expresión evaluada de forma diferida, y f() para evaluar la expresión inmediatamente.

Nota: Se dice que una promesa está establecida si se cumple o se rechaza, pero no está pendiente. También escuchará el término resuelto usado con promesas; esto significa que la promesa se establece o "bloquea" para que coincida con el estado de otra promesa. Estados y destinos contiene más detalles sobre la terminología de promesas.

Promesas encadenadas

Los métodos Promise.prototype.then(), Promise.prototype.catch() y Promise.prototype.finally() se utilizan para asociar una acción posterior con una promesa que se establece.

El método .then() toma hasta dos argumentos; el primer argumento es una función de devolución de llamada (callback) para el caso resuelto de la promesa, y el segundo argumento es una función de devolución de llamada para el caso rechazado. Cada .then() devuelve un objeto de promesa recién generado, que opcionalmente se puede usar para encadenar; por ejemplo:

js
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 300);
});

myPromise
  .then(handleResolvedA, handleRejectedA)
  .then(handleResolvedB, handleRejectedB)
  .then(handleResolvedC, handleRejectedC);

El procesamiento continúa hasta el siguiente eslabón de la cadena incluso cuando .then() carece de una función de devolución de llamada que devuelve un objeto Promise. Por lo tanto, una cadena puede omitir con seguridad cada función de devolución de llamada de rechazo hasta el .catch() final.

Manejar una promesa rechazada en cada .then() tiene consecuencias más adelante en la cadena de promesas. A veces no hay otra opción, porque un error debe manejarse de inmediato. En tales casos, debemos generar un error de algún tipo para mantener el estado de error en la cadena. Por otro lado, en ausencia de una necesidad inmediata, es más sencillo omitir el manejo de errores hasta una sentencia .catch() final. Un .catch() es realmente solo un .then() sin una ranura de argumento para una función de devolución de llamada para el caso en que se resuelva la promesa.

js
myPromise
  .then(handleResolvedA)
  .then(handleResolvedB)
  .then(handleResolvedC)
  .catch(handleRejectedAny);

Usando Expresiones de funciones de flecha para las funciones de devolución de llamada, una implementación de una cadena de promesa podría verse así:

js
promise1
  .then((value) => `${value} y barra`)
  .then((value) => `${value} y barra de nuevo`)
  .then((value) => `${value} y de nuevo`)
  .then((value) => `${value} y de nuevo)
  .then((value) => {
    console.log(value);
  })
  .catch((err) => {
    console.error(err);
  });

La condición de terminación de una promesa determina el estado "establecido" de la próxima promesa en la cadena. Un estado "resuelto" indica una finalización exitosa de la promesa, mientras que un estado "rechazado" indica una falta de éxito. El valor de retorno de cada promesa resuelta en la cadena se pasa al siguiente .then(), mientras que el motivo del rechazo se pasa a la siguiente función de manejo de rechazo en la cadena.

Las promesas de una cadena se anidan como muñecas rusas, pero se lanzan como la parte superior de una pila. La primera promesa de la cadena está anidada más profundamente y es la primera en aparecer.

(promise D, (promise C, (promise B, (promise A) ) ) )

Cuando nextValue es una promesa, el efecto es un reemplazo dinámico. return hace que se lance una promesa, pero la promesa nextValue se coloca en su lugar. Para el anidamiento que se muestra arriba, suponga que .then() asociado con "promise B" devuelve un nextValue de "promise X". El anidamiento resultante se vería así:

(promise D, (promise C, (promise X) ) )

Una promesa puede participar en más de un anidamiento. Para el siguiente código, la transición de promiseA a un estado "establecido" hará que se invoquen ambas instancias de .then().

js
const promiseA = new Promise(myExecutorFunc);
const promiseB = promiseA.then(handleFulfilled1, handleRejected1);
const promiseC = promiseA.then(handleFulfilled2, handleRejected2);

Se puede asignar una acción a una promesa ya "establecida". En ese caso, la acción (si corresponde) se realizará en la primera oportunidad asíncrona. Tenga en cuenta que se garantiza que las promesas serán asincrónicas. Por lo tanto, una acción para una promesa ya "establecida" ocurrirá solo después de que la pila se haya borrado y haya pasado un ciclo de reloj. El efecto es muy parecido al de setTimeout(action,10).

js
const promiseA = new Promise((resolutionFunc, rejectionFunc) => {
  resolutionFunc(777);
});
// En este punto, "promiseA" ya está resuelto.
promiseA.then((val) => console.log("el registro asíncrono tiene val:", val));
console.log("registro inmediato");

// produce salida en este orden:
// registro inmediato
// el registro asíncrono tiene val: 777

Seguimiento de objetos de configuración titular

Un objeto de configuración es un entorno que proporciona información adicional cuando se ejecuta código JavaScript. Esto incluye el mapa del campo y del módulo, así como información específica de HTML, como el origen. El objeto de configuración titular se rastrea para garantizar que el navegador sepa cuál usar para un código de usuario determinado.

Para representar mejor esto, podemos echar un vistazo más de cerca a cómo el campo podría ser un problema. Se puede pensar aproximadamente en un campo como el objeto global. Lo que es único acerca de los campos es que contienen toda la información necesaria para ejecutar código JavaScript. Esto incluye objetos como Array y Error. Cada objeto de configuración tiene su propia "copia" de estos y no se comparten. Eso puede causar algún comportamiento inesperado en relación con las promesas. Para evitar esto, hacemos un seguimiento de algo llamado objeto de configuración titular. Esto representa información específica del contexto del código de usuario responsable de una determinada llamada de función.

Para ilustrar esto un poco más, podemos echar un vistazo a cómo un

El mismo concepto se aplica a las promesas. Si modificamos un poco el ejemplo anterior, obtenemos esto:

html
 


Si cambiamos esto para que el