Promise.prototype.then()

El m茅todo then() retorna una Promesa. Recibe dos argumentos: funciones callback  para los casos de 茅xito y fallo de Promise.

Nota: Si ambos argumentos son omitidos, o se proveen m茅todos que no sean funciones, se crear谩 una nueva Promesa sin handlers adicionales, que simplemente adoptan el estado final de la Promesa que entonces es llamado. Si el primer argumento es omitido o se provee una no-funci贸n, el nuevo Promise que es creado simplemente adopta el  estado cumplido del Promise que entonces es llamado (si se convierte en fulfilled). Si el segundo argument es omitido o se provee una no-funci贸n, el nuevo Promise que es creado simplemente adopta  el estado de rechazo del Promesa que entonces es llamado (si se convierte en rechazado).

Sintaxis

p.then(alCumplir[, enRechazo]);

p.then(function(value) {
   // cumplimiento
  }, function(reason) {
  // rechazo
});

Par谩metros

Retorna un Promise el cual es determinado por las funciones input:

  • Si alCumplir o enRechazo arroja un error, o retorna un Promise rechazado, then retorna un Promise rechazado.
  • Si alCumplirenRechazo retorna un Promise que resuelve, o retorna cualquier otro valor, then retorna un Promise resuelto.
alCumplir Optional
Una Funci贸n es llamada si la Promesa se cumple. Esta funci贸n tiene un argumento, el valor de cumplimiento. Si no es una funci贸n, se reemplaza internamente con una funci贸n de "Identidad"  (devuelve el argumento recibido).
enRechazo Optional
Una Funci贸n es llamada si la Promesa es rechazada. Esta funci贸n tiene un argumento, la raz贸n de rechazo. Si no es una funci贸n, se reemplaza internamente con una funci贸n "Lanzador" (lanza un error que recibi贸 como argumento).

Valor de retorno

Un Promise en estado pendiente. La funci贸n de control (alCumplir o enRechazo) es llamada de forma as铆ncrona (tan pronto como el stack se vac铆e). Despu茅s de la invocaci贸n de la funci贸n de control pueden darse diferentes casos:

  • Si se recibe un valor, la Promesa devuelta por el m茅todo then queda resuelta adoptando el valor de retorno.
  • Si se produce un error, la Promesa devuelta por el m茅todo then es rechazada, adoptando el error como su valor.
  • Si se devuelve una Promesa ya resuelta, la Promesa devuelta por el m茅todo then queda resuelta adoptando el valor de la promesa anterior.
  • Si se devuelve una Promesa con un objeto pendiente de resolver, la resoluci贸n o rechazo devueltos por  then quedar谩 a esperas de que la Promesa establecida para la funci贸n de control quede resuelta. Adem谩s, el valor de la Promesa en estado pendiente ser谩 el mismo que el valor devuelto por el controlador.

Veamos un ejemplo para demostrar la asincron铆a del m茅todo then.

// al usar una promesa revuelta, el bloque 'then' se lanzar谩 autom谩ticamente,
// pero sus funciones controladoras se lanzar谩n as铆ncronamente,
// como demuestran los console.logs
var promResuelta = Promise.resolve(33);

var thenProm = promResuelta.then(funci贸n(valor){
    console.log("茅sto ser谩 invocado cuando acabe el stack principal. El valor recibido y devuelto es: " + valor);
    return valor;
});
// imprimimos al momento el valor de thenProm()
console.log(thenProm);

// usando setTimeout podemos posponer la ejecuci贸n de una funci贸n al momento en el que el stack quede vac铆o.
setTimeout(funci贸n(){
    console.log(thenProm);
});


// logs, en orden:
// Promise {[[EstadoPromise隆]]: "pendiente", [[ValorPromise]]: undefined}
// "茅sto ser谩 invocado cuando acabe el stack principal. El valor recibido y devuelto es: "33"
// Promise {[[EstadoPromise]]: "resuelta", [[ValorPromise]]: 33}

Descripci贸n

Ya que los m茅todos then y Promise.prototype.catch() devuelven promesas, pueden ser encadenados 鈥 una operaci贸n llamada composici贸n.

Ejemplos

Usando el metodo then

var p1 = new Promise(function(resolve, reject) {
  resolve('Success!');
  // or
  // reject ("Error!");
});

p1.then(function(value) {
  console.log(value); // Success!
}, function(reason) {
  console.log(reason); // Error!
});

Encadenamiento

El m茅todo then devuelve una Promise que permite encadenar m茅todos.

Puedes pasar una lambda a then y si devuelve una promesa, una Promise equivalente ser谩 expuesta al then subsecuente en la cadena de m茅todos. El fragmento incluido debajo simula un c贸digo as铆ncrono mediante la funci贸n setTimeout

Promise.resolve('foo')
  // 1. Recibe "foo", concatena "bar" con 茅l, y resuelve la cadena con el siguiente 'then'
  .then(funci贸n(hilo) {
    return new Promise(function(resolve, reject) {
      setTimeout(funci贸n() {
        hilo += 'bar';
        resolve(hilo);
      }, 1);
    });
  })
  // 2. recibe "foobar", registra una funci贸n de llamada para opear sobre ese hilo
  // e imprimirlo en la consola, pero no antes de devolver el hilo sin modificar
  // en la resoluci贸n del siguiente 'then'
  .then(funci贸n(hilo) {
    setTimeout(funci贸n() {
      hilo += 'baz';
      console.log(hilo);
    }, 1)
    return hilo;
  })
  // 3. imprime mensajes 煤tiles sobre c贸mo funcionar谩 el c贸digo en esta secci贸n
  // antes de que el hilo se procese por el c贸digo de prueba
  // antes del bloque 'then'.
  .then(funci贸n(hilo) {
    console.log("脷ltimo Then:  oops... no me he molestado en instanciar y devolver " +
                "una promesa en el then anterior, as铆 que la secuencia puede ser un poco " +
                "sorprendente");

    // Observemos que `string` no incluye el trozo 'baz' en 茅ste punto. 脡sto ocurre
    // porque lo hemos contruido para que ocurra as铆ncronamente con una funci贸n setTimeout
    console.log(hilo);
});

Cuando un valor sencillamente se devuelve desde un lambda then , devolver谩 un Promise.resolve(<valor devuelto por el controlador que haya sido invocado>).

var p2 = nueva Promise(function(resolver, rechazar) {
  resolver(1);
});

p2.then(funci贸n(valor) {
  console.log(valor); // 1
  return valor + 1;
}).then(function(value) {
  console.log(valor + '- Este uso s铆ncrono es pr谩cticamente in煤til'); // 2- Este uso s铆ncrono es pr谩cticamente in煤til
});

p2.then(funci贸n(valor) {
  console.log(valor); // 1
});

Una llamada a  then devolver谩 una promesa rechazada si la funci贸n lanza un error o devuelve una Promise rechazada.

Promise.resolve()
  .then( () => {
    // Hace que .then() devuelva una promera rechazada
    throw new Error('Oh no!');
  })
  .then( () => {
    console.log( 'No invocada.' );
  }, error => {
    console.error( 'Funci贸n de rechazo llamada: ', error );
});

En cualquier otro caso, una Promise en resoluci贸n ser谩 devuelta. El el siguiente ejemplo, el primer then() devolver谩 un 42 dentro de una Promise en resoluci贸n, aunque la Promise de la cadena fue rechazada.

Promise.reject()
  .then( () => 99, () => 42 ) // enRechazo devuelve 42, que est谩 dentro de una Promise en resoluci贸n
  .then( respuesta => console.log( 'Resuelta con ' + respuesta ) ); // Resuelta con 42

En la pr谩ctica, suele ser preferible capturar promesas rechazadas en lugar de utilizar la sintaxis de dos casos de then, como demostramos abajo.

Promise.resolve()
  .then( () => {
    // Hace que .then() devuelva una promesa rechazada
    throw new Error('Oh no!');
  })
  .catch( error => {
    console.error( 'funci贸n enRechazo invocada: ', error );
  })
  .then( () => {
    console.log( "Siempre soy invocada, incluso si la promesa del then previo es rechazada" );
  });


Tambi茅n puedes usar encadenamiento para implementar una funci贸n con una API basada en promesas, sobre una funci贸n del mismo tipo.

function traer_datos_actuales() {
  // La funci贸n fetch() de la API devuelve una Promesa. Esta funci贸n
  // expone una API similar, pero el valor de cumplimiento
  // de la Promesa de esta funci贸n tiene m谩s tareas
  // implementadas sobre ella.
  return fetch('datos_actuales.json').then((response) => {
    if (response.headers.get('content-type') != 'application/json') {
      throw new TypeError();
    }
    var j = response.json();
    // podr铆amos hacer algo con j
    return j; // valor de cumplimiento asignado al usuario de
              // fetch_datos_actuales().then()
  });
}

Si alCumplir devuelve una promesa, el valor de retorno de then ser谩 resuelto o rechazado por la promesa.

function resolverDespues(resolver, reject) {
  setTimeout(funci贸n () {
    resolver(10);
  }, 1000);
}
function rechazarDespues(resolver, reject) {
  setTimeout(function () {
    resolver(new Error('Error'));
  }, 1000);
}

var p1 = Promise.resolve('foo');
var p2 = p1.then(funci贸n() {
  // Devuelve la promesa aqu铆, que ser谩 resuelta igualada a 10 tras 1 segundo
  return new Promise(resolverDespues);
});
p2.then(funci贸n(v) {
  console.log('resuelta', v);  // "resuelta", 10
}, funci贸n(e) {
  // no invocada
  console.log('rechazada', e);
});

var p3 = p1.then(funcion() {
 // Devuelve la promesa aqu铆, que ser谩 rechazada con 'Error' despues de 1 segundo
 return new Promise(rechazarDespues);
});
p3.then(funcion(v) {
 // no invocada
  console.log('resuelta', v);
}, funcion(e) {
  console.log('rechazada', e); // "rechazada", 'Error'
});

window.setImmediate estilo polyfill basado en promesas

Usar un m茅todo Function.prototype.bind()Reflect.apply (Reflect.apply() (en-US)) para crear un (non-cancellable) setImmediate-style function.

const nextTick = (() => {
  const noop = () => {}; // literally
  const nextTickPromise = () => Promise.resolve().then(noop);

  const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args])
  const nextTick = (fn, ...args) => (
    fn !== undefined
    ? Promise.resolve(args).then(rfab(null, fn, null))
    : nextTickPromise(),
    undefined
  );
  nextTick.ntp = nextTickPromise;

  return nextTick;
})();

Especificaciones

Especificaci贸n Estado Comentario
ECMAScript 2015 (6th Edition, ECMA-262)
La definici贸n de 'Promise.prototype.then' en esta especificaci贸n.
Standard Definici贸n inicial en el est谩ndar ECMA.
ECMAScript (ECMA-262)
La definici贸n de 'Promise.prototype.then' en esta especificaci贸n.
Living Standard

Compatibilidad en navegador

No compatibility data found for javascript/promise.
Check for problems with this page or contribute missing data to mdn/browser-compat-data.

Ver tambi茅n