在SF由n͛i͛g͛h͛t͛i͛r͛e͛大大指出关于Promise中catch用的不到位的错误。贴上大大推荐的文章Promise中的菜鸟和高阶错误,文章很详细说明了一些Promise使用中的错误和指导。另外更正内容在后面补充。
从 jQuery $.Deferred() 开始
说到异步流程控制,之前用的比较多的是jQ的Deferred。那Deferred是个啥呢,不清楚没关系,直接控制台来打印看下:
喔!看得出$.Deferred()后是个对象,其下面有着熟悉的done
, fail
, always
字眼(对,,是不是有点熟悉了呢?没错!如果经常用ajax的话就会经常接触到这些货色)。 当然了,不止这些,还有最最最重要的reject
和resolve
方法,说到这两个方法,就得引出下Deferred的状态机制了——其实很简单,实例化后用上图中的state
方法就可以查看($.Deferred().state()
),有三种状态
- 执行resolve/reject前,返回值是pending
- 执行了resolve,返回值是resolved
- 执行了reject,返回值是rejected
直接来试着用下吧!这里我们假设执行一个随机延时的setTimeout
的异步操作,在setTimeout
异步操作结束后,根据延时大小,做出不同回应 ! 代码:
|
|
尝试下通俗理解整个流程就是
在某个操作开始前创建一个
Deferred
对象,然后执行操作操作间可根据情况给dfd执行
relove
或者reject
方法改变状态并传入数据最后返回出dfd的对象下的一个promise对象,这里不直接返回dfd对象是因为dfd对象的状态是在第一次resolve或者reject后还可以更改的(不过里面的数据以第一次为准)!!
操作执行后用
done
和fail
方法分别接受resolve和reject状态和数据(一一对应)然后执行回调(其实1.8还有个then
方法,接受两个参数,第一个参数为resolve
的回调,第二个为reject
的)always
是无论resolve
还是reject
都会执行。
讲个比较烂的比喻
我是一个流水线车间质检工人,就在平常的这样的一天,来了一批玩具熊,嗯,接下来应该是这样的
来了一个检查目标(
$.Dererred()
),这时你还不知道它是好是坏我靠我几十年的新东方炒菜技巧检验产品并给良品贴上了合格标签(
dfd.res* olve(合格标签)
),次品贴上回厂标签* (dfd.reject(回厂标签及原因)
)然后通过的良品和次品都来到了各自的包装口打好包,不能对里面的标签做更改了!(
dfd.promise()
)去往自己下一个目的地(return dfd.promise
)再然后良品来到了熊孩子手中(
.done()
),次品回到了厂里(.fail()
),最后不管玩具熊到了哪里,其实都会被开膛破肚(.always()
好吧这里有点牵强)
这里再上一张图来解释下!
还有值得说一下的是always
里的回调,我在实际中使用时发现总是在done
和fail
里的回调(假设为同步)执行完毕后后执行的。
金掌银掌仙人掌 掌声有请 ES6 Promise
和上面一样,先打印一下!
可以看到Promise下也有熟悉的resolve
和reject
方法,好像和jQ的Deferred
颇为相似!但是不是少了点什么呢?done
或者fail
之类的流程控制的方法呢??
不急,其实展开prototype
原型上就可以看到挂载着的then
方法了!(像极了jQ1.8后那个then
,不过我觉得应该说是jQ来遵循Promise
才对)
Promise其实就是个构造函数,还是之前的例子,这里我们分三步走
|
|
粗粗一看好像和Dererred
不能更像了,,不过细心点的话可以发现我们在韩书力直接返回了prms
这个对象,而不是像之前把羊包装了一层。。。对!因为Promise的特性就是一旦第一次赋予了状态后面就无法更改了,这也算省心多了吧。但是问题来了,所以我为什么要选择用Promise
呢??
这么说吧,它是原生的 它是原生的 它是原生的!,还有可以链式链式链式链式调用!,我们可以把每一个then
或者catch
当做一个处理器, 比如这样
|
|
对!没看错,其实在then
里面你还可以return
其他的promise
对象传并递数据!更有甚你甚至可以什么都不返回,比如说这样
|
|
有点被绕晕了吧
我们用一句话来梳理下:
链式调下会有一串then
和catch
,这些then
和catch
处理器会按照顺序接受上个处理器所产生的返回值,并且根据传入的状态做出不同响应,要么跳过,要么处理(所以上面23行处的catch
处理器被跳过了)
ps: 上面我们用的then
处理器只有一个函数参数,所以只会处理resolve
状态,如果是两个then
就可以处理reject
了。
----更新于5月11日-----
catch
使用的注意
上面一块代码中引出了catch
处理器, 之前以为 cacth()
是 then(null, ...)
的语法糖, 其实这么说不完全正确(功能层面上来说这两个是完全相同的没错——都是处理reject
和异常),但是到了实际使用中Promise中的菜鸟和高阶错误文章中给出了明确的情况证明,这里贴一下:
首先只处理异常情况,下面两个是等价的
|
|
但是,如果不只是处理异常的下面两种情况下就不一样了
|
|
不够清楚吗?那么如果是这样呢?如果第一个回调函数抛出一个错误
会发生什么?
|
|
结论就是,当使用 then(resolveHandler, rejectHandler)
, rejectHandler
不会捕获在 resolveHandler
中抛出的错误!
贴完了,好吧,这有什么用呢?
看似这个注意项并不影响平常使用,原文作者也说道:
因为,笔者的个人习惯是从不使用then方法的第二个参数,转而使用 catch() 方法
那么,问题来了,如何正确的使用catch
呢? 其实我没有很好的想明白,希望指教
,随便抛两个砖
|
|
哈哈哈哈哈哈,还是好好再去想想Promise去了,弄明白了再来补充,再次谢谢@n͛i͛g͛h͛t͛i͛r͛e͛大大,荆柯刺秦王
写的很粗糙,有错误的地方希望多多指教!!