Promise全解析(一)

78 阅读3分钟

什么是Promise

Promise在JS这门语言中占领了一个极其重要的地位,他是JS解决异步编程的一个方案。
Promise是一个类,Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值。
Promise解决了之前对于异步操作可能会导致的地狱回调的问题,并把这种嵌套回调的方式,修改为了链式的调用方式,降低了编码难度,使代码可读性明显增强。

Promise的状态

一个Promise对象存在三种状态

  • 待定(pending)
  • 兑现(fulfilled)
  • 拒绝(rejected)

待定状态时一个Promise对象最初的状态,比如创建一个Promise,然后直接在控制台打印出它,就会得到一个pending状态的Promise

let promise = new Promise(()=>{})
console.log(promise)             //Promise {<pending>}

处于待定态的Promise可以转变为两种状态,一种状态是兑现(fulfilled),一种状态是拒绝(rejected),Promise一旦改变成为其中一种状态(fulfilled或rejected)后,那么整个Promise的状态就不能被改变。
由于Promise的状态是私有的,也就是说,Promise控制状态只能在Promise内部,外部是完全访问不到的。其中控制状态是通过Promise的两个函数参数来实现的,Promise函数内部调用resolve()可以改变状态为兑现(fulfilled),调用reject()可以改变状态为拒绝(rejected)并且会抛出一个错误,如下所示。

let p1 = new Promise((resolve,reject)=>{ resolve() })
let p2 = new Promise((resolve,reject)=>{ reject() })

console.log(p1)  //Promise {<fulfilled> : undefined }
console.log(p2)  //Promise {<rejected> : undefined }    Uncaught (in promise) undefined

这两个例子中没有异步操作,在p1,p2创建的时候,他们的状态就已经确定了,原因是resolve和reject函数是同步执行
如果在调用resolve后,再次调用reject,那么reject是无效的,因为Promise状态一旦改变就无法再次变更。反之先调用reject后调用resolve也是同理。

let p1 = new Promise((resolve,reject)=>{ 
    resolve();
    reject();
})
console.log(p1)   //Promise {<fulfilled>: undefined}

Promise.resolve()

Promise在一开始不一定需要处于待定(pending)状态,通过调用Promise.resolve()可以实例化一个已经被兑现的Promise,rejected也是如此。

let p1=Promise.resolve()
let p2=Promise.reject()

console.log(p1)    //Promise {<fulfilled>: undefined}
console.log(p2)    //Promise {<rejected>: undefined}

Promise.resolve()方法接受一个参数,参数有且仅有一个,多余的参数会被忽略,若是没有参数则默认为undefined

let p1=Promise.resolve()
let p2=Promise.resolve(3,4,5)    //多余的参数会被忽略

console.log(p1)    //Promise {<fulfilled>: undefined}
console.log(p2)    //Promise {<rejected>: 3}

这个参数会随着resolve方法传递给后续的处理程序,并且这种传递是幂等性的,也就是说,不管外部嵌套了多少层resolve,他们传递的值都是一样的。如下所示

let p1 = Promise.resolve(1)
let p2 = Promise.resolve(p1)

console.log(p1)        //Promise {<fulfilled>: 1}
console.log(p2)        //Promise {<fulfilled>: 1}
console.log(p1===p2)   //true

并且resolve中可以传递任何参数,有时候会导致一些奇怪的事。。

let p1=Promise.resolve(new Error('Promise Error'))
console.log(p1)          //Promise {<fulfilled>: Error: Promise Error}  

//浏览器没有抛出错误提示

Promise.reject()

Promise.reject()与resolve类似,可以接受一个参数传递给后续的处理程序,并且也可以直接调用创造一个被拒绝的Promise(上面说过了),但是有一点不同,那就是reject()的传参不具有幂等性。如果reject包裹的参数是一个Promise,那么当前的Promise就会以这个被包裹住的Promise作为拒绝的理由,而不会持续传参。

let p1 = Promise.resolve(1)
let p2 = Promise.reject(p1)

console.log(p2)           //Promise {<rejected>: Promise}

还有一点需要注意的,就是reject中的参数信息不可以通过try/catch捕获到,而只能通过Promise本身的Promise.prototype.catch捕获。原因是try/catch只能捕获到同步的错误,它无法捕获到异步中的错误。