javascript-ES6承诺结算回调?

无论我的Promise是否成功解决,我都想执行相同的操作。 我不想将相同的功能绑定到.then的两个参数。是否没有像jQuery一样的.always? 如果没有,我该如何实现?

mpen asked 2020-07-31T22:36:33Z
7个解决方案
34 votes

像jQuery一样没有finally吗?

不,还没有。 尽管有一个积极的建议,但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)
    );
};

两者都确保原始解析得以维持(当回调中没有异常时),并确保等待诺言。

Bergi answered 2020-07-31T22:41:51Z
9 votes

使用async / await,您可以将awaitawait结合使用,如下所示:

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

这是我使用Babel的异步生成器插件在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();
    }
  });
}

我在Mocha测试中和Sequelize ORM一起使用此代码来启动数据库事务,并且无论测试中数据库调用的结果如何,总是在最后回滚。

这大致类似于Bluebird的await方法,但是IMO,语法好得多!

(注意:如果您想知道为什么我不在第一个Promise上使用await-这是Sequelize的实现细节。它使用CLS将SQL事务“绑定”到Promise链中。在同一链中发生的任何事情都是 因此,在Promise上等待将“关闭”交易区块并破坏了链条,我举了这个示例向您展示如何将“香草” Promise处理与异步功能混合使用 ,并一起玩。)

Lee Benson answered 2020-07-31T22:42:30Z
3 votes

如果您不/不能更新原型,最终破解的方法是:

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
});
user2426679 answered 2020-07-31T22:42:51Z
1 votes

这是我对.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
Chong Lip Phang answered 2020-07-31T22:43:15Z
1 votes

摘要:

现在,我们还可以访问onfullfilled。此功能可以放在promise链中,作为执行某些清理工作的最后一个元素。 与Promise.finallyPromise.catch相比,它的工作方式如下:

  • onfullfilled仅在promise解析后被调用(如果仅将其放在第一个参数回调函数中)
  • onfullfilled仅在拒绝诺言时被调用
  • 当履行诺言时,总是会调用onfullfilled,因此当诺言被拒绝或解决时,两者都会被调用。

例:

onfullfilled

在上面的示例中,我们可以看到始终执行onfullfilled,无论诺言是否得以解决。 并不是说理想的情况是Promise.finally应该始终在promise链的末尾进行一些清理,无论Promise的结果如何,都应执行该清理。

使用onfullfilled的优点是,它避免了代码重复,因为它针对已解决和已拒绝的承诺执行。 否则,我们将不得不使用以下黑客:

.then(onfullfilled, onfullfilled)

要么

.then(onfullfilled)
.catch(onfullfilled)

请注意,现在我们必须将onfullfilled函数定义为promisehandler自身之外的命名函数(或传入2个匿名函数副本,这甚至不那么优雅)。 Promise.finally为我们解决了这个问题。

Willem van der Veen answered 2020-07-31T22:44:17Z
0 votes

无需引入新概念

const promise = new Promise((resolve, reject) => {
  /*some code here*/
});

promise.then(() => {
  /* execute success code */
}, () => {
  /* execute failure code here */
}).then(() => {}, () => {}).then(() => {
  /* finally code here */
});
Luis Banegas Saybe answered 2020-07-31T22:47:16Z
0 votes

扩展Bergi答案。

在catch处理程序中返回Promise.reject()将阻止最终确定“ then”被调用。

因此,如果您要处理2次以上的Promise错误,则应使用如下样板:

return myPromise()
.then(() => ... )
.catch((error) => {
  ...
  myFinnaly();
  return Promise.reject(error);
})
.then(() => myFinnaly());
Nikita answered 2020-07-31T22:47:45Z
translate from https://stackoverflow.com:/questions/32362057/es6-promise-settled-callback