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()分支的返回值被丢弃,不是吗?