关于 Promise

什么是 Promise

我们都知道 JavaScript 是一门单线程异步的语言,实现异步我们传统的方式是使用回调函数和事件,但是随着前端的发展,该模式面临着两个问题:

  1. 回调地狱:某个异步操作需要等待之前的异步操作完成,无论用回调还是事件,都会陷入不断的嵌套
  2. 异步之间的联系:某个异步操作要等待多个异步操作的结果,对这种联系的处理,会让代码的复杂度剧增

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件,更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。

ES6的异步模型

在了解 Promise 之前,先来看看 ES 官方总结的一套异步处理模型,理解这套模型,能更好的理解 Promise

  1. 一件可能发生异步操作的事情,分为 unsettled 阶段和 settled 阶段
    在这里插入图片描述

    • unsettled:未决阶段,表示事情还在进行前期的处理,并没有发生通向结果的那件事
    • settled:以决阶段,表示事情已经有了一个结果,结果无论好坏,整件事无法逆转

    事情总是从 unsettled 逐步发展到 settled 并且,未决阶段拥有控制何时通向已决阶段的能力

  2. 一件事被划分为三种状态: pendingresolvedrejected

    • pending:表示这件事情还在挂起(最终的结果还没出来)
    • resolved:表示整件事情已经出现结果,并是一个可以按照正常逻辑进行下去的结果
    • rejected:表示整件事情已经出现结果,并是一个无法按照正常逻辑进行下去的结果,通常用于表示有一个错误

    既然未决阶段有权力决定事情的走向,因此,未决阶段可以决定事情最终的状态

    • 把事情变为 resolved 状态的过程叫做:resolve,推向该状态时,可能会传递一些数据
    • 把事情变为 rejected 状态的过程叫做:reject,推向该状态时,可能会传递一些数据,通常为错误信息
      在这里插入图片描述
  3. 当事情达到 settled 后,通常需要进行后续处理,不同的已决状态,决定了不同的后续处理

    • resolved 状态:这是一个正常的 settled,后续处理表示为 thenable
    • rejected 状态:这是一个非正常的 unsettled,后续处理表示为 catchable

    后续处理可能有多个,因此会形成作业队列,这些后续处理会按照顺序,当状态到达后依次执行
    在这里插入图片描述
    所谓的 Promise 就是整个过程
    在这里插入图片描述

基本使用

Promise 对象是一个构造函数,用来生成 Promise 实例,未决阶段的处理会立即执行(Promise 新建后就会立即执行)

resolvereject 均可以传递最多一个参数,表示推向状态的数据

const promise = new Promise((resolve, reject)=>{
    // 未决阶段的处理立即执行
    if (Math.random() < 0.5) {
        resolve(1)
    } else {
        reject(new Error('出错了'))
    }
});

通过 Promise.prototype.then 注册 resolved 和 rejected 状态的函数

promise.then(data => {
    // thenable 处理函数
},err => {
    // catchable 处理函数
})

通过 Promise.prototype.catch 注册 rejected 状态的函数

promise.catch(err => {
    // catchable 处理函数
})

thenable 和 catchable 函数都可以注册多个,执行时会按照注册顺序执行

注意点

  1. 运行到注册 thenable / catchable 函数时,如果 Promise 的状态已决,该函数会立即执行;如果是未决,则会加入到作业队列,等待到达resolved / rejected 状态后再执行

  2. thenable / catchable 函数是异步的,也就是说第二点的立即执行说的不准确,应该是放入事件队列的微任务队列等待同步函数执行完再执行

    const promise = new Promise((resolve, reject)=>{
        setTimeout(() => {
            resolve(1)
        }, 1000);
    });
    
    console.log(promise); 
    promise.then(data => console.log(data));
    console.log(promise);
    // pending
    // pending
    // 1
    
  3. 在未决阶段的处理函数中,如果发生未捕获的错误,会将状态推向 rejected,并会被 catchable 函数捕获

    const promise = new Promise((resolve, reject)=>{
        throw new Error('出错了')
    });
    
    console.log(promise); 
    promise.catch(err => console.log(err));
    // rejected
    // Error: 出错了
    
  4. 一旦状态推向了已决阶段,无法再对状态做任何更改,也就是说,一旦状态变为 resolved / rejected 再执行 reject / resolve 函数或者抛出错误是没有办法再改变状态的

    const promise = new Promise((resolve, reject)=>{
        throw new Error('出错了');
        resolve(1);
    });
    
    console.log(promise); 
    promise.then(data => console.log(data), err => console.log(err));
    // rejected
    // Error: 出错了
    
  5. 如果 resolve 的参数是另一个 Promise,则该 Promise 的状态和参数由那个 Promise 参数的状态决定

    const promise1 = new Promise((resolve, reject) => {
        reject(1);
    })
    
    const promise2 = new Promise((resolve, reject) => {
        resolve(promise1);
    })
    
    promise2.then(data => console.log(data), err => console.log('err', err));
    
    console.log(promise1 === promise2)
    // false
    // err 1
    
  6. 如果 reject 参数的另一个参数是 Promise,则该 Promise 的状态为 rejectederr 参数为传入的参数 Promise

    const promise1 = new Promise((resolve, reject) => {
        reject(1)
    })
    
    const promise2 = new Promise((resolve, reject) => {
        reject(promise1)
    })
    
    promise2.then(data => console.log(data), err => console.log('err', err))
    // err Promise {<rejected>: 1} 
    

Promise 的串联

Promise.prototype.thenPromise.prototype.catch 函数可以注册已决阶段处理的函数,并且他们都返回一个新的 Promise,该 Promise 的状态由当前的 Promise 的状态决定

  1. 只有当当前的 Promise 的状态已决并且处理函数执行完该 Promise 的状态才会从 pendding 变为 resolved / rejected,并且 thenable / catchable 函数的返回值就是这个新的 Promise 的数据

  2. 无论这个 Promisethen 函数还是 catch 返回的,只要该处理函数没有抛出未捕获的错误,新的 Promise 的状态一定是 resolved

    const promise1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1)
        }, 1000);
    })
    
    const promise2 = promise1.then(data => {
        console.log(data);
        return 2;
    })
    
    console.log(promise1, promise2)
    
    setTimeout(() => {
        console.log(promise1, promise2);
    }, 1000);
    
    //pending pending
    // 1
    // fulfilled 1   fulfilled 2
    
  3. 如果前面的 Promise 的后续处理,返回的是一个 Promise,则返回的新的 Promise 状态和后续处理返回的 Promise 状态保持一致,并且数据也一致

    const promise1 = new Promise((resolve, reject) => {
        resolve(1)
    })
    
    const promise2 = promise1.then(data => {
        console.log(data);
        return new Promise((resolve, reject) => {
            reject(2)
        })
    })
    
    console.log(promise1, promise2)
    
    setTimeout(() => {
        console.log(promise2);
    }, 1000);
    // fulfilled 1  pending
    // 1
    // rejected  2
    
  4. catchable 函数可以捕获前面所有未捕获的错误

    new Promise((resolve, reject) => {
        resolve(1);
    }).then(data => {
        // ...
    }).catch(err => {
        //...
    }) // 可以捕获前面所有的错误
    

其他API

  1. Promise.prototype.finally [ ES 2018 ]

    thencatch 一样使用,但是 finally 注册函数没有参数,并且无论 Promiseresolved 还是 rejected 都会执行

  2. Promise.resolve

    该方法返回一个 resolved 状态的 Promise,传递的数据作为状态数据

    相当于:

    new Promise((resolve, reject) => {
        resolve(err);
    });
    

    如果传递的数据是一个 Promise ,则直接返回该 Promise

    const promise1 = new Promise((resolve, reject) => {
        resolve(1)
    })
    const promise2 = Promise.resolve(promise1)
    console.log(promise1 == promise2)
    // true
    

    如果传入的参数是一个 thenable对象,会将这个对象转为 Promise 对象,然后就立即执行 thenable 对象的then()方法

    thenable 对象指的是具有 then方法的对象

    const thenable = {
        then(resolve, reject) {
            console.log(1)
            resolve(42);
        }
    };
    
    const p1 = Promise.resolve(thenable);
    p1.then(function (value) {
        console.log(value); 
    });
    // 1
    // 42
    
  3. Promise.reject

    等同于

    new Promise((resolve, reject) => {
        reject(err);
    });
    
  4. Promise.all(iterable)

    该方法返回一个 Promise 对象,该对象在 iterable 参数对象里所有的 Promise 对象都 resloved 的时候才会 resolved,只要有一个 rejectedPromise 对象就会 rejected;该对象 thenable 的参数为一个包含所有 iterablePromise 的返回值,该对象的 catchable 的参数为 iterable 里第一个触发失败的 Promise 对象的错误信息

  5. Promise.race(iterable)

    该方法返回一个 Promise 对象,该对象在 iterable 参数对象里所有的 Promise 对象都 resloved 的时候才会 resolved,只要有一个 rejectedPromise 对象就会 rejected;该对象 thenable 的参数为一个包含所有 iterablePromise 的返回值,该对象的 catchable 的参数为 iterable 里第一个触发失败的 Promise 对象的错误信息

  6. Promise.race(iterable)

    看名字就可以看出来(看哪个 Promise 先完成),当 iterable 参数里的任意一个子 Promise 成功或失败后;返回的 Promise 马上也会用子 Promise 的成功返回值或失败详情作为参数调用该对象相应的 thenablecatchable

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值