理解Promise

177 阅读3分钟

异步编程

JavaScript代码在执行的时候是单线程的,可以理解为只能按照代码出现的顺序,从上到下一行一行的执行,但是遇到了异步的行为,比如定时器,那就需要等到同步代码执行完成后的一段时间里再去执行异步代码。

Promise

Promise首先是一个对象,它通常用于描述现在开始执行,一段时间后才能获得结果的行为(异步行为),内部保存了该异步行为的结果。然后,它有一个有状态的对象:

  • pending:待定

  • fulfilled:兑现

  • rejected:拒绝 一个Promise只有这3种状态,且状态的转换过程有且只有2种:

  • pending到fulfilled

  • pending到rejected 可以通过Promise构造器创建一个Promise

const promise = new Promise((resolve, reject) => {
  resolve('哈哈哈')
})

传递给new Promise的是executor执行器、当Promise被创建的时候,executor会立即同步执行。executor函数里通常做了2件事情:初始化一个异步行为和控制状态的最终转换。

const promise = new Promise((resolve, reject) => {
  setTimeout(()=>{
    resolve()
  },1000)
})

如上代码所示,setTimeout函数用来描述一个异步行为,而resolve用来改变装填。

executor函数包含2个参数,他们都是回调函数,用于控制Promise的状态转换。

  • resolve:用来将状态pending转换成fulfilled
  • reject:用来将状态pending转换成rejected 一个promise的状态一旦被转换过,则无法再变更
const promise = new Promise((resolve, reject) => {
  setTimeout(()=>{
    resolve('哈哈')
    resolve('哈哈11')
    reject('哈哈222')
  },1000)
})
console.log(promise) // Promise {<fulfilled>: "哈哈"}

可以看到执行2次resolve函数,1次reject函数,但是promise的最终结果只取了第一次的resolve

由new Promise构造器返回的Promise对象具有如下内部属性:

  • PromiseState:最初是pending,resolve被调用的时候变为fulfilled,或者reject被调用时会变为rejected
  • PromiseResult:最初是undefined,resolve(value)时被调用变为value,或者在reject(error)被调用改为error。

Promise实例方法

Promise.prototype.then()

Promise.prototype.then()将用于Promise实例添加处理程序的函数。它接受2个可选的参数:

  • onResolved:状态由pending转换成fulfilled时执行
  • onRejected:状态由pending转换成rejected时执行
function onResolved(res){
  console.log(`resolved${res}`)  //resolved哈哈哈
}
function onRejected(err){
  console.log(`rejected${err}`)
}
new Promise((resolve, reject) => {
  resolve('哈哈哈') 
}).then(onResolved,onRejected)

因为状态的变化只有2种,所以onResolved和onRejected在执行的时候必定是互斥。

new Promise((resolve, reject) => {
    resolve()
}).then(res => {})
new Promise((resolve, reject) => { 
    reject() 
}).then(null, err => {})

如果给then()函数传递来了非函数参数,则会默认忽略

Promise.prototype.catch()

Promise.prototype.catch()用于给Promise对象添加拒绝处理程序。只接受一个参数:onRejected函数。实际上,下面这两种写法是等效的:

function onRejected(err){}
new Promise((resolve, reject) => {
    reject()
}).catch(onRejected)
new Promise((resolve, reject) => {
    reject()
}).then(null, onRejected)
Promise.prototype.finally()

Promise.prototype.finally()用于给Promise对象添加onFinally函数,这个函数主要是做一些清理的工作,只有状态变化的时候才会执行该函数

function onFinally() {
    console.log('哈哈哈')  // 并不会执行  
}
new Promise((resolve, reject) => {
    
}).finally(onFinally)

因为onFinally函数是没有任何参数的,所以在其内部其实并不知道该Promise的状态是怎么样的

链式调用

new Promise((resolve, reject) => {
    resolve()
}).then(() => {
    console.log('A')
    new Promise((resolve, reject) => {
        resolve()
    }).then(() => {
        console.log('B')
    }).then(() => {
        console.log('C')
    })
}).then(() => {
    console.log('D')
})
基于onResolved生成一个新的Promise

Promise.prototype.then()会返回一个新的Promise

let p1 = new Promise((resolve, reject) => {
  resolve(3)
})
let p2 = p1.then(() => 6)
setTimeout(console.log, 0, p1)   //Promise {<fulfilled>: 3}
setTimeout(console.log, 0, p2)   //Promise {<fulfilled>: 6}

可以看到p1和p2的内部PromiseResult是不一样,说明p2是一个新的Promise实例。

新产生的Promise会基于onResolved的返回值进行构建,构建的时候其实是把返回值传递给Promise.resolve()生成的新实例。

如果.then()没有提供onResolved这个处理程序,则Promise.resolve()会基于上一个是咯resolve后的值来初始化一个新的实例

let p1 = new Promise((resolve, reject) => {
    resolve(3)
})
let p2 = p1.then()
setTimeout(console.log, 0, p2)  // Promise {<fulfilled>: 3}

如果onResolved处理程序没有返回值,那么返回的新实例的内部值会是undefined:

let p1 = new Promise((resolve, reject) => {     
     resolve(3) 
}) 
let p2 = p1.then(() => {}) 
setTimeout(console.log, 0, p2)  // Promise {<fulfilled>: undefined}

写不下去了,剩下的自行理解