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(...)
1
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; } ); } ); } |
2
otakustay 2015-07-15 10:34:56 +08:00
代码自己拿去格式化吧,gist太麻烦
|
3
otakustay 2015-07-15 10:37:55 +08:00
另外你的“finally要在所有then和catch完成后执行”的说法是错的,仔细想想是不是“catch要在then后执行”呢?毕竟是先try后catch嘛
Promise的then和catch是一种“衍生”,即会“生”出一个新的Promise来,相当于串行模式下从一个函数跳到了另一个函数,而之前的finally是“前一个函数中的finally”,所以并不是如你说的finally要在最后 |
4
redyyu OP 你给的这一段我在提问前自己也写过了。它虽然可以捕获 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 中提过你提供的这一段代码,我觉得这个只是一个凑合的办法,而且它仅仅是方便了 链式调用,写死最后的那一下。 |
5
xieranmaya 2015-07-17 10:31:16 +08:00 1
这么实现会不会看着简单一些?
Promise.prototype.finally = function(fn) { function finFn(valueORreason){ fn.call(null) } this.then(finFn, finFn) return this } |
6
xieranmaya 2015-07-17 11:10:44 +08:00
调整了一下,这样可以保证finally一定最后执行,但是finally返回的是this而不是一个新的Promise
https://gist.github.com/xieranmaya/5f817d85823dcb108fc9 |
7
xieranmaya 2015-07-17 11:28:28 +08:00
如果想要返回一个新的Promise,this.then一下就好了
|
8
rekey 2015-07-27 11:12:31 +08:00
我只是来看妹纸的。
|
9
redyyu OP @xieranmaya 好像行。
|