Promise是ES6中新增的一个对象,主要是为了解决异步操做的问题而新增的一个方法数组
Promise用来表示一个异步的状态(成功/失败)以及返回的值异步
也就是说,Promise里放着的是将来要作的事情函数
关于执行的顺序,Promise对象在建立后会当即执行,then在当前全部同步脚本执行完后执行对象
例如以下案例blog
输出的顺序为:Promise、Hello、resolved图片
解析以下:字符串
1.Promise对象建立后当即执行,所以输出了Promise回调函数
2.then对象中的语句要到当前脚本全部同步任务执行完后再执行,因此resolved暂时不输出,先输出Hello同步
3.最后,当前脚本内全部的同步任务执行完,执行then里的语句,resolved输出it
下面一个案例也是关于异步同步问题的
输出结果为:123465
过程以下:
1.一、四、6不用过多说明,同步任务,按照代码的前后依次执行便可
2.Promise实例在建立的时候就马上执行,因此2和3也依次输出
3.因为then方法是在全部同步任务执行完后执行,因此5最后输出
Promise里共有三种状态:进行中(pending)、成功(fulfilled)、失败(rejected)
其中状态的改变称为决议,而状态只能够从pendding变动到fulfilled/rejected,不可逆也不可在fulfilled/rejected里互换
也就是说在Promise里,只有pending--->fulfilled或者pending--->rejected,没有第三种
使用时,须要先构建一个Promise对象的实例
这个实例接收两个参数,一个是回调成功时执行的函数(习惯性命名resolve),另外一个是回调失败时执行的函数(习惯性命名reject)
而若是想在某次回调后继续链式回调,则返回构建Promise对象实例的函数,这样一来,就是返回了一个Promise实例,继续等待传入回调成功和失败时的执行函数
固然,还能够向resolve和reject里传入参数,回调的时候能够输出,但只能够传入一个参数,多余的参数不被接收
使用的时候,利用Promise实例中的then方法,接收两个参数,第一个为回调成功时执行的函数(resolve),第二个是回调失败时执行的函数(reject)
而若是想链式调用,则直接在执行完resolve/reject后返回Promise实例,这样一来,下次继续等待传入两个回调函数
实际上也能够不返回Promise实例,这样一来then里的函数会同以前全部Promise实例后的then一同执行
例如这里的1和2都是1s后输出的,而345则是12输出后的1s后输出(由于返回的Promise实例是要1s后回调的),能够理解成输出1后返回了一个“啥也没干”的Promise
then里若是想返回Promise实例,return必定要写在then的执行函数后面
Promise里能够传入reject函数来对错误进行处理,若是没有,须要用catch语句来接收错误并处理
该段代码的执行顺序以下:
1.由于给test输入了true,因此执行的是resolve函数,这里resolve函数传入的参数是ok,而then里的data只是个形参,执行的最后返回Promise对象并传入false
2.第二个链式调用的then里,只传入了resolve函数,没有reject函数,但因为这里Promise对象里是false,应该执行reject函数,因此没有输出
3.第三个链式调用为catch,捕获了第二个then里没有捕获的错误,里面传入的参数能够理解为reject函数,e为形参,最后输出404
可是,若是错误被reject处理了,那后面的catch就不起做用
实际上,能够在最后的catch里再次返回一个错误,让后面的catch解决,但会出现一个问题,有可能最后一个catch抛出了错误,可是没有解决。这一点上,ES6暂时没有解决方法
Promise实例中还有个finally方法,能够放在链式调用的最后,其中的代码不管如何都会执行
注意若是finally执行时还有错误未处理,则会报错,说明Promise里的错误未处理
Promise提升了代码的可读性和可维护性
Promise的使用最大的好处是,解决了以前多层嵌套回调的问题
例如,咱们须要建立一个回调函数,用来在1s后执行咱们传入的一个函数,若是说只是回调一次,直接调用这个回调函数,传入1s后执行的函数,便可
但若是是要依赖上一次回调的结果,再去执行一次回调函数,那就须要嵌套两层了,不过也还行
可若是是嵌套到五六层呢?嵌套了这么多层之后,若是须要更改其中两次的执行顺序呢?彷佛就没办法操做了,堪称回调地狱(以下图)
可若是使用Promise对象来写这一段代码,就变成了下面的样子
相比于以前的层层套的写法,这里采用了链式调用的方法,若是哪里须要修改内容或顺序,能够直接修改then里的内容,或者调整then的顺序,解决了多层嵌套的问题
用来接收一个数组,里面每一项是一个Promise实例,最后包装成一个新的Promise实例
注意这里传入的必须是数组(可迭代),不然会报错(not iterable)
分三种状况:
1.全部的Promise决议为成功,.all的决议也为成功,把全部Promise实例的resolve中传入的参数组成一个数组返回,其顺序符合Promise实例的顺序
2.有一个Promise决议为失败,.all决议为失败,把这个决议失败的reject传入的参数做为错误返回
有多个Promise决议为失败时,输出的参数只有第一个reject传入的参数
3.传入空数组,决议为成功,输出then中给resolve传入的参数
相似于all,race里传入的参数也是Promise实例,不过返回时,按照第一个返回的决议决定race的决议状况,执行then里的resolve或reject
若是返回的速度同样,则按照传入时的第一个Promise实例的决议来决定执行resolve/reject
但若是传入的为空,则什么都不执行,会一直“挂”在那里
这里的resolve和reject不是Promise实例或者then里传入的参数,而是Promise实例的方法,用来生成被决议为成功/失败的Promise实例
也就是说,不管传入的是什么,resolve/reject返回的都是一个Promise实例
resolve方法中能够传入:
1.普通值(字符串、数字等)
下图中的两种写法其实是同样的
也就是说,then方法最后返回时,能够直接用Promise.resolve()/reject()返回一个决议成功/失败的Promise实例
另外,Promise的all方法里,数组中的每一项都会被resolve方法包裹一下,这样每一项都是一个Promise实例
2.Promise实例
这里传入的Promise实例最后经过resolve方法输出的仍为该实例(最底下一行有验证)
3.thenable对象
thenable对象是一个相似于then方法的对象,传入resolve后,会当即执行其中的then方法,按照then方法的套路走
这里的执行结果为“我被执行了”和“哼”
过程以下:
1.obj做为一个thenable对象被传入的resolve方法,而后后面的then方法执行时,调用obj里的then方法
2.这里的回调函数cb就是console.log(data),也就是输出哼,但在这以前先输出“我被执行了”
而Promise.reject()相比于resolve简单得多,会把传入其中的值直接当成错误信息输出
能够用then变成异步任务并在当前脚本全部同步任务执行后再执行的特性,把同步任务变成异步任务
上方的执行结果为:我是同步任务、我变成了异步任务、2
具体过程以下:
1.用createAsyncTask函数,传入一个匿名函数,这个函数因为传入了Promise的resolve方法,变成了一个Promise实例,可是执行是在后面的then里,所以变成了异步任务,稍后执行
2.“我是同步任务”直接输出
3.输出全部同步语句后,对then里的语句进行执行,因为这里两句都是同步任务,因此按顺序输出
能够利用Promise的各类方法实现当图片所有加载完后再载入
(案例待补充)