无论我的Promise是否成功解决,我都希望运行相同的操作。我不想将同一个函数绑定到.then
的两个args。不是像jQuery那样的.always
吗?如果没有,我该如何实现?
答案 0 :(得分:31)
是不是像jQuery一样有
.always
?
不,there's not (yet)。虽然有active proposal,但也许是ES2018。
如果没有,我该如何实现?
您可以像这样自己实施finally
方法:
Promise.prototype.finally = function(cb) {
const res = () => this
const fin = () => Promise.resolve(cb()).then(res)
return this.then(fin, fin);
};
或更广泛地说,将解析信息传递给回调:
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)
);
};
两者都确保原始分辨率得以维持(当回调中没有异常时)并且等待承诺。
答案 1 :(得分:9)
使用async / await,您可以await
与try/finally
的组合,如下所示:
async function(somePromise) {
try {
await somePromise();
} finally {
// always run this-- even if `somePromise` threw something
}
}
这是我使用Babel的async-to-generator插件在Node生产中运行的一个真实示例。
// 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();
}
});
}
我在Sequelize ORM旁边的mocha测试中使用此代码来启动数据库事务,无论测试中的数据库调用结果如何,总是在最后回滚。
这大致类似于Bluebird的.finally()
方法,但是IMO,语法更好!
(注意:如果你想知道为什么我不是await
第一个Promise-这是Sequelize的一个实现细节。它使用CLS来'绑定'一个SQL事务到一个Promise链。任何在内部同一个链的东西都限定在事务中。外面的任何东西都没有。因此,等待Promise将“关闭”事务阻止并打破了链条。我把这个例子放进去向你展示如何将“vanilla”Promise处理与异步函数混合在一起,并且可以很好地协同工作。)
答案 2 :(得分:3)
如果你不能/不能更新原型,那么最终破解的方法是:
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
});
答案 3 :(得分:1)
这是我对.finally()的实现。
Promise.prototype.finally = function(cb) {
return this.then(v=>Promise.resolve(cb(v)),
v=>Promise.reject(cb(v)));
};
我测试了它:
(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
答案 4 :(得分:0)
无需引入新概念
.categories:first-child {
display:none;
}
答案 5 :(得分:0)
扩展 Bergi 回答。
在catch处理程序中返回Promise.reject()将阻止finnalizing'then'被调用。
因此,如果你要处理2次以上的承诺错误,你应该使用这样的样板:
return myPromise()
.then(() => ... )
.catch((error) => {
...
myFinnaly();
return Promise.reject(error);
})
.then(() => myFinnaly());
答案 6 :(得分:0)
allSettled最终可以直接工作:
Promise.allSettled([promiseSuccess, promiseReject])
.then(results => console.log);
检查:https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled