Promise浅析

1.首先,promise是什么

promise是一种异步编程的解决方法。

2.为什么用promise

为了解决多个异步回调难以维护和控制的问题。
例如:多个定时器嵌套的做法

   setTimeout(function () {
        console.log(1)
        setTimeout(function () {
          console.log(2)
          setTimeout(function () {
            console.log(3)
          }, 1000)
        }, 1000)
      }, 1000)

首先,这种做法一眼看上去,就没有组织性,不够简洁。如果,再往每个定时器里面写业务逻辑,那么,就显得很乱,没有章法,不好维护。这就是传统异步编程的缺点。

3.promise的基础用法

(1)promise对象有三种状态,分别为pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果能决定是哪种状态。

(2)Promise构造函数接受一个函数作为参数:

  • Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve和reject,他们是两个函数,由Javascript引擎提供,不用自己部署。

  • 接受的这个函数叫executor函数,即执行函数。它在Promise构造函数执行时,立即调用执行,它内部一般是一个异步操作。一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。

  • resolve函数的作用是,将promise对象的状态从“pending”变为‘’resolved‘’,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。这里需要注意下,resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样:

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

  • reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
    即如下实例:
  • 注意:Promise 的状态一旦改变,就永久保持该状态,不会再变了。也就是,如果executor函数中还有能改变promise状态的语句,该语句不会被调用了,then方法中的回调函数也只会被执行一次
var promise = new Promise( function( resolve, reject) {
       //some code 
      if(//异步操作成功){
        resolve(value); //将value传给成功的回调函数,即then方法的第一个参数函数
         }else{
         reject(error);
         }
});

4.promise错误捕获

(1)promise对异步编程中的错误捕获处理,也更为合理。

  • 虽然then方法的第二个参数可以用于捕获异步操作中的错误,但更建议用catch方法来捕获错误。
  • 若then方法中写了Promise状态变为rejected的回调函数,则即使后面有catch也不会调用的。
  • 如果没有指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。Promise 内部的错误不会影响到 Promise 外部的代码。
// bad
promise
  .then(function(res) {
    // success
  }, function(rej) {
    // error
  });

// good
promise
  .then(function(res) { //cb
    // success
  }, function(rej) { // 抛出的错误会被该函数捕获,下面的catch方法不执行。
  	
  })
  .catch(function(err) {
    // error
  });

(2)catch方法可以捕获promise链中任何一环抛出的错误。并且,会返回新的Promise实例,后面有then方法的话,会继续执行的。

 function fn() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('error')
            }, 1000)
        })
    }
    fn().then(() => {
        console.log('第一个then'); // 不执行
    }).then(() => {
        console.log('第二个then'); // 不执行
    }).catch((error) => {
        console.log(error);
    }).then(() => {
     // 该函数在catch方法执行完后,接着执行。(因为他是新的Promise实例的方法)
    })

(3)关于错误捕获注意点

  • promise对象中的异步操作(一般是一个异步函数)结果失败时,用reject()函数抛出错误。
const promise = new Promise(function(resolve, reject) {
setTimeout(() => {// 模拟异步操作
          try {
            throw new Error('test');
          } catch(e) {
            reject(e);
          }
        }, 300)

});
promise.catch(function(error) {
  console.log(error);
});

不能这样写:
在异步函数中抛出的错误不会被捕获到

const readTime = function (value, time = 500) {
      return new Promise(function (resolve, reject) {
        setTimeout(() => {
            throw new Error('test');
        }, 300)
      });
    };

    readTime()
      .then(res => {
        console.log(res);
      })
      .catch(e => {
        console.log('e===',e);
    });

上述定时器中的错误,catch是捕获不到的。

5.Promise.all

  • Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);

上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例

  • p的状态由p1、p2、p3决定,分成两种情况。
    (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。数组中返回值的顺序,和传入的Promise实例的顺序一样。
    (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数(有两种可能,一是then方法中写了rej状态的回调,二是写了catch方法)。
  const p1 = new Promise((resolve, reject) => {
    resolve('p1--hello');
  }).then(result => result)

  const p2 = new Promise((resolve, reject) => {
    reject('p2--hello');
  }).then(result => { // 该函数不会执行的,因为promise实例的状态为rejected
    return result
  })

  Promise.all([p1, p2])
    .then(res => {
      console.log('res所有promise都执行完==');
      console.log(res)
    }, rej => {
      console.log('rej所有promise都执行完==');
      console.log(rej) // 打印 'p2--hello'
    })
    .catch(e => { // 这里不会执行的,因为then方法中有rejected的回调了。
      console.log('error所有promise都执行完==');
      console.log(e)
    });
  • 等待Promise.all()方法接受的所有promise实例的状态全都改变了(不管是成功还是失败)之后,才会执行Promise.all后面的回调函数。
 const p1 = new Promise((resolve, reject) => {
    console.log('p1执行==');
    resolve('hello');
  }).then(result => result);

  const p2 = new Promise((resolve, reject) => {
    console.log('p2执行==');
    throw new  Error('报错了');
  }).then(result => {
    console.log(result);
  })

  Promise.all([p1, p2])
    .then(res => {
      console.log('res所有promise都执行完==');
      console.log(res)
    })
    .catch(e => { // 等p1,p2内部异步操作执行完后,执行该方法
      console.log('error所有promise都执行完==');
      console.log(e)
    });

  • 注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

上面代码中,p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例该实例执行完catch方法后,会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。

  • 当多个异步操作(一般是请求数据)没有继发关系的时候,Promise.all()可用于多个异步操作并发。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值