谈谈对Promise的一些理解(面试常问)

123 阅读5分钟

一、对Promise的理解

Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的信息,它的出现大大改善了异步编程的困境,避免了回调地狱,它比传统回调函数更合理与利于维护,让代码的可读性更高。 所谓Promise,简单说九是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,它可以获取异步操作的信息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

(1)Promise的实例有三个状态

  • Pending(进行中)
  • Resolved(已完成)
  • Rejected(已拒绝) 当把一件事情交给Promise时,它的状态就是Pending,任务完成了状态就变成Resolved,没有完成失败了就变成Rejected

(2)Promise的实例有两个过程

  • pending->fulfilled已完成
  • pending->rejected已拒绝 注意:一旦从进行状态变为其他状态就永远不能更改状态了。

Promise的特点

  • 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending进行中、fulfilled已完成、rejected已失败。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是Promise这个名称的由来——“承诺”
  • 一旦状态改变就不会再变。Promise的状态改变,只有两种可能:pending=>fulfilled;pending=>rejected。这时称为resolved已定型。

Promise的缺点

  • 无法取消Promise,一旦建立它就会立即执行,无法中途取消
  • 如果不设置回调函数,Promise内部抛出的错误不会反应到外部
  • 处于pending时,无法得知目前进展到哪个阶段(刚开始或即将完成)

总结

Promise对象是异步编程的一种解决方案。Promise是一个构造函数,接收一个函数作为惨呼,返回一个Promise实例。一个Promise实例有三种状态,分别是pending、resolved和rejected,分别代表进行中、已完成和已失败。实例的状态只能由pending转变为resolved或rejected状态,并且状态一旦改变,就无法再次修改。 状态的改变通过resolve()与reject()函数来实现,可以在异步操作结束后调用这两个函数改变Promise实例的状态,它的原型上定义了一个then方法,使用then方法可以为两个状态的改变注册回调函数。回调函数属于微任务,会在本轮事件循环的末尾执行。

二、Promise的基本用法

(1)创建Promise对象

一般情况下会使用new Promise()来创建Promise对象

const promise = new Promise((resolve,reject)=>{
    if(/*异步操作成功*/){
        resolve(value)
    } else {
        reject(error)
    }
})

// 使用resolve方法和reject方法
const testPromise = (ready) => {
    return new Promise((resolve,reject)=>{
        if(ready){
            resolve("hello world")
        } else {
            reject("No thanks")
        }
    })
}
// 方法调用
testPromise(true).then((msg)=>{
console.log(msg)
},(err)=>{
console.log(err)
})

(2)Promise方法

// Promise是一个对象,也是一个构造函数

/*
.then方法:用于处理Promise的成功状态,接受两个参数:一个成功回调函数和一个可选的失败回调函数。成功回调函数接收Promise对象的解决值作为参数。
.catch方法:用于处理Promise对象的失败状态,接受一个失败回调函数作为参数。失败回调函数接收Promise对象的拒绝原因作为参数。
.finally方法:用于在Promise对象的状态改变时执行一些操作,它接受一个回调函数作为参数,该回调函数
*/

// 1.Promise.resolve
// 将现有对象转为Promise对象
Promise.resolve("laoshu")
// 等价于
new Promise(resolve=>resolve("laoshu"))

// 2.Promise.reject
// Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected
const p = Promise.reject("error")
// 等同于
const p = new Promise((resolve,reject)=>reject('error'))

// 3.Promise.all
// Promise.all()方法用于将多个Promise实例,包装成一个新的Promise实例
const p = Promise.all([p1,p2,p3])
/*
p的状态由p1,p2,p3决定,分成两种情况。
1.只有p1,p2,p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1,p2,p3的返回值组成一个数组,传递给p的回调函数。
2.只要p1,p2,p3中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
*/

// 4.Promise.race
// Promise.race()方法同样是将多个Promise实例,包装成一个新的Promise实例。
const p = Promise.race([p1,p2,p3])
// 上面代码中,只要p1,p2,p3之中有一个实例率先改变状态,p的状态就跟着改变,那个率先改变的Promise实例的返回值,就传递给p的回调函数。

// 5.Promise.allSettled
// Promise.allSettled()方法,用来确定一组异步操作是否都结束了(不管成功或失败),所以,它的名字叫做“Settled”,包含了“fulfilled”和“rejected”两种情况

// 6.Promise.any
// 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态,如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。


三、Promise.all和Promise.race的区别和使用场景

(1)Promise.all

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回但是一个结果数组,而失败的时候返回的是最先被reject失败状态的值 Promise.all中获得的成功结果里的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,这样当遇到发送多个请求顺序获取和使用数据的场景,都可以使用Promise.all来解决。

(2)Promise.race

顾名思义,Promise.race就是赛跑的意思,Promise.race([p1,p2,p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。