ES6承诺已解决回调
ES6 promise settled callback?
无论Promise是否成功解析,我都希望运行相同的操作。我不想将同一个函数绑定到.then
的两个参数。难道没有像jQuery那样的.always
吗?如果没有,我该如何实现?
难道没有像jQuery那样的
.always
吗?
不,还没有。虽然有一个积极的提案,所以可能是ES2018。
是的,有:promise .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)
);
};
两者都确保原始决议是持续的(当回调中没有异常时(,并确保等待承诺。
使用async/await,您可以将await
和try/finally
组合在一起,如下所示:
async function(somePromise) {
try {
await somePromise();
} finally {
// always run this-- even if `somePromise` threw something
}
}
这是我在生产中使用Node运行的一个真实例子,使用Babel的异步到生成器插件。
// 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一起使用这段代码来启动DB事务,无论测试中DB调用的结果如何,总是在最后回滚。
这大致类似于Bluebird的.finally()
方法,但IMO,更好的语法!
(注意:如果你想知道我为什么不在第一个Promise上await
,这是Sequelize的一个实现细节。它使用CLS将SQL事务"绑定"到Promise链。在同一个链内发生的任何事情都会被限制在事务的范围内。在外部发生的任何事情不是。因此,等待Promise会"关闭"事务块并破坏我抛出这个例子是为了向您展示如何将"香草"Promise处理与异步函数混合在一起,并能很好地发挥作用。(
如果你不/不能更新原型,最后破解的方法是:
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((.的实现
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
摘要:
我们现在也可以访问Promise.prototype.finally()
。这是一个可以作为最后一个元素放在promise链上执行一些清理的函数。与Promise.then
和Promise.catch
相比,它的工作方式如下:
- 仅当promise被解析时调用
Promise.then
(如果您只将其作为第一个参数回调函数( - 当承诺被拒绝时,仅调用
Promise.catch
Promise.finally
总是在promise已满时被调用,因此在promise被拒绝或解决时两者都被调用
示例:
let Prom = new Promise((res, rej) => {
let random = Math.random();
if (random > 0.5) {
res(1);
} else {
rej('Error occured')
}
});
Prom.then((val) => {
console.log(val);
return val * 10;
}).catch((err) => {
console.log(err);
}).finally(() => {
console.log('finally executed');
})
在上面的例子中,我们可以观察到,无论promise是解决还是拒绝,finally
总是被执行的。并不是说finally
在理想情况下应该总是在promise链的末尾进行一些清理,不管promise结果如何,都应该执行这些清理。
使用finally
的优点是,它避免了代码重复的需要,因为它是针对已解决的承诺和已拒绝的承诺执行的。否则,我们将不得不使用类似的黑客:
.then(onfullfilled, onfullfilled)
或
.then(onfullfilled)
.catch(onfullfilled)
请注意,现在我们必须将onfullfilled
函数定义为promisehandler本身之外的命名函数(或者传入2个匿名函数副本,这就更不优雅了(。Promise.finally
为我们解决了这个问题。
无需引入新概念
const promise = new Promise((resolve, reject) => {
/*some code here*/
});
promise.then(() => {
/* execute success code */
}, () => {
/* execute failure code here */
}).then(() => {}, () => {}).then(() => {
/* finally code here */
});
扩展Bergi答案。
在catch处理程序中返回Promise.rejectt((将阻止对要调用的'then'进行finalizing。
因此,如果你要处理承诺错误2次以上,你应该使用这样的样板:
return myPromise()
.then(() => ... )
.catch((error) => {
...
myFinnaly();
return Promise.reject(error);
})
.then(() => myFinnaly());
allSettled直接作为finally工作:
Promise.allSettled([promiseSuccess, promiseReject])
.then(results => console.log);
检查:https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
- AngularJS:我可以跳过函数参数回调吗
- 测试Angular Service解决错误回调中的promise
- 比“类似回调的行为”更好的解决方案
- 我可以将 $(this) 传递给 .getJSON 回调函数吗?任何解决方法
- JS加载顺序 - 滚动JS禁用,回调解决方案,或者更简单
- 用于绑定 JS 对象以进行回调的解决方案
- 实现回调函数的自定义解决方案
- 谷歌放置了api回调解决方法
- 什么's在javascript回调函数中使用blade的解决方案
- 如果我使用循环,如何解决回调函数
- 加载多个图像时用于回调的跨浏览器解决方案
- 解决node.js类初始值设定项上的回调地狱
- 承诺API回调-如何正确解决或拒绝
- 投票系统(多个站点),没有回调的顶部列表的解决方案
- 模块化如何在技术上解决nodejs中的回调地狱?
- ES6承诺已解决回调
- chrome.tabs.executeScript的回调在我想要它之前被调用,需要解决方案
- “这个”的解决方案回调内部的引用更改
- SQLite回调的高效解决方案
- 在外部回调中解决/拒绝承诺