Promise可以理解为一个容器,里面保存了某个未来才会结束的事件(通常是一个异步操作)。

如果我们需要根据这个事件的结果,做响应的后续操作,放在以前,后续操作基本放到了callback里面,要和这个事件紧密耦合在一起。

但是有了promise这个容器,我们就可以把这个事件包装起来,当我们需要做处理的时候,我们再拿到这个proisme容器做相应处理,这样就实现了在代码上的解耦。

1 特点:

1.1 异步操作有三种状态

pending(进行中)、fulfilled(已成功)、 Rejected(已失败)。promise对象状态只根据异步操作结果决定当前状态,其他任何操作都无法改变这个状态。

1.2 一旦状态改变,就保持这个状态,不会再改变。

即使状态已经发生,再对promise对象添加回调函数,也会立即得到这个结果。

2 缺点:

2.1 一旦新建promise,就会立即执行,无发取消

2.2 如果不设置回调函数,promise内部抛出的错误不会反应到外部

2.3 处于pending状态时,无发知道操作进展的阶段

3 promise实例的基本语法:

  1. var promise = new Promise(function(resolve,reject){
  2. // some code 异步操作
  3. if(异步操作成功){
  4. resolve(value) // 改变状态pendding-->resolved,并把结果传递出去
  5. } else {
  6. reject(error) // pendding-->rejected
  7. }
  8. })
  9. promise
  10. .then(function(value){//成功回调}, function(error){ //失败回调})
  11. .then(....)
  12. .catch(function(err){})

3.1 失败回调是可选项

3.2 then()方法指定的回调函数会在脚本同步任务执行完成后,才会执行(mirco task)

  1. new Promisefunctionresolvereject){
  2. console.log(1 // 注意 这个函数里面的代码属于同步代码
  3. resolve()
  4. })
  5. .then(function(){console.log(2)})
  6. console.log(3)
  7. // 打印顺序
  8. 1
  9. 3
  10. 2

3.3 resolve/reject并不会终结Promise的参数函数的执行

  1. new Promisefunctionresolvereject){
  2. resolve() // resolve以后,一般应该在then回到里面进行处理,所以一般 return resolve()
  3. console.log(1)
  4. }).thenfunction(){console.log(2)})
  5. // 打印
  6. 1
  7. 2

3.4 假如promiseA里面 resolve(promiseB),一个异步操作的结果是返回另一个异步操作,则promiseB的状态会传给PromiseA(promiseA的状态就有promiseB的状态来决定)

  1. var p1 = new Promise(function(resolve,reject){
  2. setTimeout(()=>{
  3. reject(new Error('fail'))
  4. },3000)
  5. })
  6. var p2 = new Promise(function(resolve,reject){
  7. setTimeout(()=>{
  8. resolve(p1)
  9. },1000)
  10. })
  11. p2
  12. .then(funtion(){
  13. console.log(1)
  14. })
  15. .catch(funtion(err){
  16. console.log(err)
  17. })
  18. // 打印
  19. fail

3.5 then方法返回另一个promise实例,故可以链式调用

then方法回调函数里面return的值,将会作为参数传递给链式中下一个then方法回调函数

  1. p2
  2. .then(funtion(){
  3. return 3
  4. })
  5. .then(function(value){
  6. console.log(value)
  7. })
  8. // 打印
  9. 3

如果return 一个promise实例,则then方法返回的promise实例状态,将会被return 的promise实例来决定
参考: 3.4 就会明白

同时要分清楚then返回的promise实例和调用then方法的实例不是同一个,是另外一个,一般链式调用来做连续关联操作,如果不关联,则可以

  1. let p1 = new Promisefunction(){...})
  2. p1.then(f1,f2)
  3. xxxxxxxxxxxxxxxxxxxxx其他业务逻辑
  4. p1.then(f3,f4)
  5. 对同一个promise实例连续调用then挂载回调,这样也做到了 对扩展开放,对修改封闭这一原则

3.6 catch方法可以捕获promise内部 or then方法抛出的错误

如果没有catch方法,promise内部错误不会传递到外层(在浏览器,不会终止脚本执行,但是会在console打印出来)
catch是then(null,function(err){})的别名
promise对象的错误会“冒泡”,会一直向后传递,直到被catch捕获为止。
catch方法仍然返回一个promise,故可以链式调用

4 Promise构造函数上挂载的方法

4.1 Promise.resolve([data])

返回一个promise实例,且实例fulfilled(已成功)

  1. Promise.resolve(1)
  2. .then((data)=> {console.log(data)})
  3. // 1

4.2 Promise.reject([data])

返回一个promise实例,且实例failed(已失败)

  1. Promise.reject(123)
  2. .then((data)=> {console.log('success'+data)},
  3. (data)=> {console.log('failed'+data)})
  4. // failed123

4.3 Promise.all(arr)

arr元素必须是promise实例。 返回promise实例,且只有数组里面所有的promise都完成,返回的promise才会是fullfiled(已成功)
并且then(arr => {}),返回的数据也是数组
都成功

  1. Promise.all([Promise.resolve(2),Promise.resolve(4),Promise.resolve(8)])
  2. .then((data)=> {
  3. console.log(data[0])
  4. console.log(data[1])
  5. console.log(data[2])
  6. })
  7. // 2
  8. // 4
  9. // 8

有一个失败

  1. Promise.all([Promise.resolve(2),Promise.resolve(4),Promise.reject(8)])
  2. .then((data)=> {
  3. console.log(data[0])
  4. console.log(data[1])
  5. console.log(data[2])
  6. })
  7. // 无任何打印信息

4.3 Promise.race(arr)

arr元素必须是promise实例。 返回promise实例,且只要数组里面某一个promise完成,返回的promise就会是fullfiled(已成功)
并且then(res => {}, err => {}), 返回的是第一个成功/失败的返回的数据

  1. Promise.race([Promise.resolve(2),Promise.resolve(4),Promise.reject(8)])
  2. .then((data)=> {
  3. console.log(data)
  4. })
  5. // 2
  1. Promise.race([Promise.reject(2),Promise.reject(4),Promise.reject(8)])
  2. .catch((data)=> {
  3. console.log(data)
  4. })
  5. // 2

案例:

前端交互操作的封装
https://www.cnblogs.com/whitewolf/p/promise-best-practice.html