Javascript ES6承诺解决回调?
无论我的承诺成功与否,我都希望执行相同的操作。我不想将同一个函数绑定到Javascript ES6承诺解决回调?,javascript,ecmascript-6,es6-promise,Javascript,Ecmascript 6,Es6 Promise,无论我的承诺成功与否,我都希望执行相同的操作。我不想将同一个函数绑定到的两个参数。难道没有像jQuery那样的。总是?如果没有,我如何做到这一点 难道没有像jQuery那样的。总是 没有。虽然有一个,但可能是ES2018。 是的,有:是自ES2018以来标准的一部分 如果没有,我如何做到这一点 您可以自己实现最终方法,如下所示: Promise.prototype.finally = function(cb) { const res = () => this const f
的两个参数。难道没有像jQuery那样的。总是?如果没有,我如何做到这一点
难道没有像jQuery那样的。总是
没有。虽然有一个,但可能是ES2018。
是的,有:是自ES2018以来标准的一部分
如果没有,我如何做到这一点
您可以自己实现最终
方法,如下所示:
Promise.prototype.finally = function(cb) {
const res = () => this
const fin = () => Promise.resolve(cb()).then(res)
return this.then(fin, fin);
};
return myPromise()
.then(() => ... )
.catch((error) => {
...
myFinnaly();
return Promise.reject(error);
})
.then(() => myFinnaly());
或者更广泛地说,通过向回调传递解析信息:
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)
);
};
这两种方法都可以确保原始解决方案得到维持(回调中没有异常时),并确保承诺得到等待。使用async/await,您可以将await
与try/finally
组合使用,如下所示:
async function(somePromise) {
try {
await somePromise();
} finally {
// always run this-- even if `somePromise` threw something
}
}
下面是一个真实的例子,我使用巴贝尔的插件在生产中运行Node
我在mocha测试中使用此代码与启动DB事务一起使用,并且无论测试中DB调用的结果如何,始终在测试结束时回滚
这大致类似于Bluebird的.finally()
方法,但在我看来,它的语法要好得多
(注意:如果你想知道为什么我没有等待第一个承诺-这是Sequelize的一个实现细节。它用于将SQL事务“绑定”到承诺链。在同一个链内发生的任何事情都是在该事务的范围内。在该承诺之外发生的任何事情都不是。因此,等待承诺将是不可能的“关闭”事务块并断开链。我加入此示例是为了向您展示如何将“普通”承诺处理与异步函数混合在一起,并一起很好地发挥作用。)如果您不/不能更新原型,破解a的最终方法是:
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
});
下面是我的.finally()的实现
我测试了它:
(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
不需要引入新概念
const promise = new Promise((resolve, reject) => {
/*some code here*/
});
promise.then(() => {
/* execute success code */
}, () => {
/* execute failure code here */
}).then(() => {}, () => {}).then(() => {
/* finally code here */
});
扩展答案
在catch处理程序中返回Promise.reject()将阻止调用finaling'then'
因此,如果您要处理承诺错误2次以上,您应该使用以下样板文件:
Promise.prototype.finally = function(cb) {
const res = () => this
const fin = () => Promise.resolve(cb()).then(res)
return this.then(fin, fin);
};
return myPromise()
.then(() => ... )
.catch((error) => {
...
myFinnaly();
return Promise.reject(error);
})
.then(() => myFinnaly());
总结:
我们现在还可以访问Promise.prototype.finally()
。这是一个函数,可以作为最后一个元素放在Promise链上执行一些清理。与Promise.then
和Promise.catch
相比,它的工作方式如下:
Promise。然后在解析Promise时只调用
(如果您只将其放在第一个参数回调函数中)
Promise.catch
只有当承诺被拒绝时才会调用
Promise。最后
始终在承诺已满时被调用,因此在承诺被拒绝或解决时都会调用
例子:
let Prom=新承诺((res,rej)=>{
设random=Math.random();
如果(随机>0.5){
决议(1);
}否则{
rej('发生错误')
}
});
Prom.then((val)=>{
控制台日志(val);
返回值*10;
}).catch((错误)=>{
控制台日志(err);
}).最后(()=>{
log(“最终执行”);
})
所有结算的工程直接作为最终工程:
Promise.allSettled([promisessuccess,promiseReject])
.then(results=>console.log);
检查:您不能这样做。最后(function(){…})?请参阅@CharlieWynn,它在Babel中未定义且未在上列出。您可以在时尝试包,我认为此错误回调。然后pollyfill中的应该抛出而不是返回。@dfsq:它通过返回原始的、被拒绝的承诺来实现:-)您是对的,这个
是最初的承诺,因为=>
,当然。您的第一个示例与它有相同的问题,不是吗?不过,我不确定您的“更广泛”解决方案。您的第一个实现(没有值)似乎与一致,所以这很好:-)为什么不使用异步函数事务
并放弃该调用,然后再调用它呢?太好了!从未想过将try/finally
与async/await
一起使用。这会派上用场的。@Bergi-Sequelize使用一种称为“CLS”的东西将事务块范围限定到承诺链。如果我使用了await
,它将返回一个事务处理程序,但随后的SQL将在块之外,因此不适用于事务。这是Sequelize的一个实现细节,我不认为这是一样的。看。我们实际上可以在不修改原型的情况下使用Bergi的解决方案。你只需要说它有趣:finallyFunc.call(promise,callback)
。与bind运算符配合得很好。这会导致第一个.then()分支的返回值被丢弃,不是吗?