认识 Promise

Promise 是什么?

Pormise 是一个对象,也是一个构造函数。

function f1(resolve, reject) {
    // 异步代码...
}
const p1 = new Promise(f1)

上面的代码中,f1 是一个用来处理异步操作的函数,Promise 接受这个函数作为参数,返回一个 Promise 实例。

Promise 的设计思想

所有的异步任务都返回一个 Promise 实例。Promise 实例有一个 then() 方法,用于指定下一步的回调函数。

const p1 = new Promise(f1);

p1.then(f2)

上面的代码中, f1 异步函数执行完后,就会执行 f2

Promise 对象的状态

Promise 对象共有三种状态:

  1. pending : 表示异步操作未完成。
  2. fulfilled : 表示异步操作成功。
  3. rejected : 表示异步操作失败。

其中,fulfilledrejected 表示异步操作已完成。

Promise 对象的状态变化只能由未完成变为已完成,也就是说,Promise 最终只能有两种结果。

  • 异步操作成功: 状态由 pending 变为 fulfilled
  • 异步操作失败:状态由 pending 变为 rejected

Promise 构造函数

object, Array 一样,JavaScript 提供 Promise 构造函数,用以生成一个 Promsise 对象实例。


const p1 = new Promise(function (resolve, reject) {
    if(/*异步操作成功 */) {
        resolve(value)
    }
    else {
        reject(new Error())
    }
}) 

在上面的例子中,Promise 构造函数接受一个函数作为参数,该函数有两个参数:

  • resolve: 用于在异步操作成功后将结果返回,并改变 Promise 实例的状态(pending - fulfilled)。
  • reject: 用于在异步操作出错时将错误传递出去,并改变 Promise 实例状态(pending - rejected)。

Promise.prototype.then()

1. 使用方式

Promise 实例的 then 方法,用来添加回调函数。

这个方法能够接受两个参数:

  • 第一个参数:处理异步操作成功时 resolve 的结果。
  • 第二个参数:处理异步操作失败时 reejct 的结果。

这个方法将会返回一个 Promise 对象。这个对象的状态要分情况讨论。


const p1 = new Promise((resolve, reject) => {
    resolve("成功");
})

p1.then(console.log, console.error);
// 成功
const p2 = new Promise((resolve, reject) => {
    reject('失败');
})’
p2.then(console.log, console.error);
// 失败
2. 链式调用

then 方法支持链式调用,即上一个 then 方法仍然会返回一个Promise 实例,我们可以继续调用 then 方法。

const p1 = new Promise(resolve => resolve('p1 成功;'))
    
    .then((res) => {
        return new Promise(resolve => resolve(res + 'step1  成功'))
    })
    .then(
    console.log,
    console.error
);
// p1 成功;step1 成功

上例中,p1 实例将异步操作结果(此时为“p1 成功”)返回给 then 的第一个参数(这个参数是个函数),接着,执行这个参数,又返回一个 Promise 对象,并将操作成功(此时为“p1 成功;step1 成功”)的结果使用 resolve 传递给下一个 then 的第一个参数,最终,这个参数将这个结果打印出来。

4. then()方法返回的 Promise 实例的状态

前面讲过,调用then 方法会返回一个 Promise 对象,而每个 Promise 对象都是有状态的,那对于不同情况下的返回值,它们的状态是怎样的?

我们可以根据 then 方法的返回值进行判断:

  1. 如果 then 方法内部返回了一个[普通]参数值,那么返回的 Promise 状态就是 resolved, value 值即是 return 的那个值。

    const promise = new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('success');
        },2000)
    });
    
    promise.then(function(data) {
        // 内部返回一个普通参数值2
        return 2; 
    })
    .then((data) => {
        console.log(data); // 2
    })
    
    第一个then 返回的 promise : {
        [[PromiseStatus]]: "resolved"
        [[PromiseValue]]: 2
    }
    
  2. 如果 then 方法内部返回一个promise 实例,那么then返回的 promise 对象就是就是这个实例,他们的状态和value均一致。

    const promise = new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve('success');
            }, 2000)
        });
    
    promise.then(function (data) {
    // 返回一个promise 实例
    return new Promise( (resolve, reject) => {
        resolve('返回一个状态为 resolve 的 promises 实例');
      });
    })
    .then((data)=> {
      console.log(data); // 返回一个状态为 resolve 的 promises 实例
    })
    
    第一个then 返回的 promise : {
        [[PromiseStatus]]: "resolved"
        [[PromiseValue]]: '返回一个状态为 resolve 的 promises 实例'
    }
    
  3. 如果 then 方法不返回任何值,那么返回的 Promise 状态就是resolved, value 为 undefined。

    const promise = new Promise(function (resolve, reject) {
      setTimeout(function () {
        resolve('success');
      }, 2000)
    });
    
    promise.then(function (data) {
      // 不返回任何值
      console.log('333333');
    })
    .then((data)=> {
      console.log(data); // undefined
    });
     第一个then 返回的 promise : {
        [[PromiseStatus]]: "resolved"
        [[PromiseValue]]: undefined
    }
    
  4. 如果 then 方法中抛出了一个异常,那么返回的 Promise 将会变成拒绝状态,value 是异常的 reason。

    new Promise((resolve, reject) => {
        if (true) {
            resolve();
        } else {
            reject();
        }
    }).then((data) => {
        resolve();
    }, (error) => {
        reject();
    })
    then返回的promise: { 
      [[promiseStatus]]: 'rejected', 
      [[promiseValue]]: 'ReferenceError: resolve is not defined at Promise.then'
    }
    
3. 报错传递性

对于链式调用,我们不用为每一个then方法都传入第二个参数来处理reject 的结果。最后一个 then 方法将会捕获到前面最后一次reject 出的结果。

const p1 = new Promise((resolve, reject) => reject('p1 失败;'))
  .then((res) => {
    return new Promise(resolve => resolve(res + 'step1  成功'))
  })
  .then((res) => {
    return new Promise(resolve => resolve(res + 'step2  成功'))
  })
  .then(
    console.log,
    console.error
  );
  
  // p1 失败

在上面的例子中,p1 reject 的结果我们不用在下一个 then 方法中就进行截获,最有一个 then 方法传入第二个参数便可以获取到。这便是Promise 的报错传递性。

Promise.prototype.catch()

then() 方法类似,catch() 方法是用来指定 Promise 对象错误状态下的回调函数,等同于 .then(null, (err) => {...})

不同之处在于 .catch() 方法不仅能够捕获Promise 对象 reject 出的错误,还能捕获到 resolve 方法执行过程中发生的错误。

由于上面提到的promise 报错具有传递性,因此建议在 Promise 语句末尾只 .catch() 语句来代替在 then 语句中传入第二个参数的形式。

另外,promise 还有很多其他的 API ,由于用的不多,就不做介绍了。更具体的可以直接看阮一峰老师的《es6标准入门》。

参考

  1. es6 标准入门-阮一峰
  2. promise.then
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值