ES6承诺解决回调?

时间:2015-09-02 20:01:03

标签: javascript ecmascript-6 es6-promise

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

7 个答案:

答案 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,您可以awaittry/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