objects ejemplo ecmascript array javascript ecmascript-6 es6-promise

javascript - ejemplo - ES6 promesa de devolución de llamada establecida?



reduce javascript ejemplo (7)

Quiero ejecutar la misma acción si mi promesa se resolvió con éxito o no. No quiero vincular la misma función a ambos .then de .then . ¿No hay un. .always como jQuery tiene? Si no, ¿cómo puedo lograr esto?


¿No hay un. .always como jQuery tiene?

No, no hay (todavía) . Aunque hay una propuesta activa , entonces tal vez ES2018.

Si no, ¿cómo puedo lograr esto?

Puede implementar el método de finally usted mismo de esta manera:

Promise.prototype.finally = function(cb) { const res = () => this const fin = () => Promise.resolve(cb()).then(res) return this.then(fin, fin); };

o más ampliamente, con pasar información de resolución a la devolución de llamada:

Promise.prototype.finally = function(cb) { const res = () => this return this.then(value => Promise.resolve(cb({state:"fulfilled", value})).then(res) , reason => Promise.resolve(cb({state:"rejected", reason})).then(res) ); };

Ambos aseguran que la resolución original sea sostenida (cuando no hay excepción en la devolución de llamada) y que se esperan promesas.


Resumen:

Ahora también tenemos acceso a Promise.prototype.finally() . Esta es una función que se puede poner en la cadena de promesa como un último elemento para realizar una limpieza. funciona de la siguiente manera en comparación con Promise.then y Promise.catch :

  • Promise.then solo recibe una llamada cuando se resuelve la promesa (si solo le pone la función de devolución de llamada de primer argumento)
  • Promise.catch solo se llama cuando se rechaza la promesa
  • Promise.finally siempre se llama cuando se Promise.finally una promesa, por lo tanto, cuando la promesa se rechaza o se resuelve.

Ejemplo:

let Prom = new Promise((res, rej) => { let random = Math.random(); if (random > 0.5) { res(1); } else { rej(''Error occured'') } }); Prom.then((val) => { console.log(val); return val * 10; }).catch((err) => { console.log(err); }).finally(() => { console.log(''finally executed''); })

En el ejemplo anterior, podemos observar que finally siempre se ejecuta independientemente de si la promesa se resuelve o rechaza. No es que finally , idealmente, siempre esté al final de la cadena de promesa para hacer una limpieza que se ejecute independientemente del resultado de la promesa.

La ventaja de usar finally es que evita la necesidad de duplicar el código porque se ejecuta tanto para una promesa resuelta como para una rechazada. De lo contrario, tendríamos que usar hacks como:

.then(onfullfilled, onfullfilled)

o

.then(onfullfilled) .catch(onfullfilled)

Tenga en cuenta que ahora tenemos que definir la función onfullfilled como una función con nombre fuera del propio controlador de promesa (o pasar 2 copias de funciones anónimas que es aún menos elegante). Promise.finally resuelve este problema.


Aquí está mi implementación de .finally ().

Promise.prototype.finally = function(cb) { return this.then(v=>Promise.resolve(cb(v)), v=>Promise.reject(cb(v))); };

Lo probé:

(new Promise((resolve,reject)=>{resolve(5);})).finally(x=>console.log(x)); //5 (new Promise((resolve,reject)=>{reject(6);})).finally(x=>console.log(x)); //6 (new Promise((resolve,reject)=>{reject(7);})) .then(x=>x,y=>y) .catch(x=>{throw "error";}) .finally(x=>{console.log(x); throw "error"; return x;}) // 7 .then(x=>console.log(x),y=>console.log(''e'')); //e // Uncaught (in promise) undefined


Con async / await, puede una combinación de await con try/finally , así:

async function(somePromise) { try { await somePromise(); } finally { // always run this-- even if `somePromise` threw something } }

Aquí hay un ejemplo real que tengo en producción con Node, usando el complemento async-to-generator Babel.

// Wrap promisified function in a transaction block export function transaction(func) { return db.sequelize.transaction().then(async t => { Sequelize.cls.set(''transaction'', t); try { await func(); } finally { await t.rollback(); } }); }

Utilizo este código dentro de una prueba de mocha junto con Sequelize ORM para iniciar una transacción de base de datos, e independientemente del resultado de las llamadas de base de datos dentro de la prueba, siempre retrocedo al final.

Esto es más o menos análogo al método .finally() Bluebird, pero en mi opinión, ¡una sintaxis mucho mejor!

( Nota : en caso de que se pregunte por qué no estoy await la primera Promesa, es un detalle de implementación de Sequelize. Utiliza CLS para ''vincular'' una transacción SQL a una cadena Promise. Cualquier cosa que ocurra dentro de la misma cadena está limitado a la transacción. Cualquier cosa externa no lo está. Por lo tanto, esperar en la Promesa habría "cerrado" el bloque de la transacción y roto la cadena. Lancé este ejemplo para mostrarle cómo el manejo de la promesa "vainilla" se puede mezclar junto con asíncrono funciones y jugar bien juntos.)


No es necesario introducir nuevos conceptos.

const promise = new Promise((resolve, reject) => { /*some code here*/ }); promise.then(() => { /* execute success code */ }, () => { /* execute failure code here */ }).then(() => {}, () => {}).then(() => { /* finally code here */ });


Para extender la respuesta de Bergi .

Devolver Promise.reject () en el controlador catch evitará que se llame a finnalizing ''then''.

Entonces, si va a manejar el error de promesa más de 2 veces, debe usar repetitivo como este:

return myPromise() .then(() => ... ) .catch((error) => { ... myFinnaly(); return Promise.reject(error); }) .then(() => myFinnaly());


Si no puede / no puede actualizar el prototipo, la forma de hackear finalmente es:

executeMyPromise() .then(function(res){ return {res: res}; }) .catch(function(err){ return {err: err}; }) .then(function(data) { // do finally stuff if (data.err) { throw data.err; } return data.res; }).catch(function(err) { // handle error });