ES6 原生的 Promise 只有 then 和 catch 没有 finally,谁有靠谱的方式加上?

2015-07-14 19:49:18 +08:00
 redyyu

ES6 原生的 Promise 只有then 和 catch 没有 finally,谁有靠谱的方式加上?

已知的不太靠谱方法,有自己增加一个属性的方式finally,在里面调用 then 或者 catch 但这样只是一个then和catch的合体,并不是真的finally,它不会排在所有 then 所有 catch之后执行。

例如
promise = new Promise(...)
promise.finally().then()
这里后面的 then 会在 finally之后执行,
而真正的finally 应该在所有的 then 或者 catch 完结以后执行。
手工把finally写最后只是掩耳盗铃,
不能假设从此后这个promise不再增加其他的 then 或者catch

比如
promise.then().finally()
....

if xxx:
promise.then(...)

20388 次点击
所在节点    JavaScript
9 条回复
otakustay
2015-07-15 10:34:48 +08:00
finally比较好加,按照现在社区的讨论,finally的特点如下:

1. 不接收任何参数,原来的value或者Error在finally里是收不到的
2. 处理后不影响原Promise的状态,该reject还是reject,该resolve还是resolve
3. 不影响Promise向后传递的传,resolve状态还是传递原来的value,reject状态还是传递原来的Error

所以代码这样就行了

Promise.prototype.finally = function (callback) {
var Promise = this.constructor;
return this.then(
function (value) {
Promise.resolve(callback()).then(
function () {
return value;
}
);
},
function (reason) {
Promise.resolve(callback()).then(
function () {
throw reason;
}
);
}
);
}
otakustay
2015-07-15 10:34:56 +08:00
代码自己拿去格式化吧,gist太麻烦
otakustay
2015-07-15 10:37:55 +08:00
另外你的“finally要在所有then和catch完成后执行”的说法是错的,仔细想想是不是“catch要在then后执行”呢?毕竟是先try后catch嘛

Promise的then和catch是一种“衍生”,即会“生”出一个新的Promise来,相当于串行模式下从一个函数跳到了另一个函数,而之前的finally是“前一个函数中的finally”,所以并不是如你说的finally要在最后
redyyu
2015-07-15 21:31:52 +08:00
你给的这一段我在提问前自己也写过了。它虽然可以捕获 chain 之前的 then 或者 catch 然而并没有什么卵用,看下面这个链

```coffee
ajax(url)
.then ->
go_uniqlo()
.then ->
meet_girl()
.catch ->
throw new Error('Impotence')
.finally ->
fuck in the dressing room ...

```

那么这里的都需要代码写下之时手动写好,
如果在后面动态加入

.then ->
pick_up_cell_phone()
.then ->
open_video_app()

会排在finally 后面 丧失了 finally 的意义,这样的情况之前用 finally 只要用then 替代 就可以了
而且相信 在现实使用中,极少极少会有 情况说是 在 链式调用 半路当中 需要 同时处理 成功和错误两种情况之后,还要继续 then 或者 catch 下去的。

而我之前说的这种 链式调用 已经安排好以后 又由其他条件加入的情况 可以很常见。
我在之前一个 angular material 的项目中平凡使用这种方式 在页面上显示 Toast (上传文件,全部传完,所有链式调用跑完,显示toast,中途添加文件,链数增加,finally 依旧在最后 显示 toast)

因此,你理解的finally 和我说的 finally 不同。

在这里我希望可以实现 angularjs 中 的 q deff 的 finally 效果。

这个也其他的promise 实现中也有叫 complete 或者 done 的。

它需要能够排在链式调用的最后一位,无条件执行。
也相当于 switch 函数的 default

对于这个问题,我现在基本上确定要么用其他的库,ES6 本身的 Promise 并没有这个,也许以后也不会有,在他们的 issues 中提过你提供的这一段代码,我觉得这个只是一个凑合的办法,而且它仅仅是方便了 链式调用,写死最后的那一下。
xieranmaya
2015-07-17 10:31:16 +08:00
这么实现会不会看着简单一些?

Promise.prototype.finally = function(fn) {
function finFn(valueORreason){
fn.call(null)
}
this.then(finFn, finFn)
return this
}
xieranmaya
2015-07-17 11:10:44 +08:00
调整了一下,这样可以保证finally一定最后执行,但是finally返回的是this而不是一个新的Promise
https://gist.github.com/xieranmaya/5f817d85823dcb108fc9
xieranmaya
2015-07-17 11:28:28 +08:00
如果想要返回一个新的Promise,this.then一下就好了
rekey
2015-07-27 11:12:31 +08:00
我只是来看妹纸的。
redyyu
2015-07-27 19:01:57 +08:00
@xieranmaya 好像行。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/205715

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX