学习笔记:Promise

143 阅读2分钟

Promise

为了解决回调地狱而生
1.promise的基本使用:

一、使用

  new Promise((resolve,reject) => {
     setTimeout(() => {
        console.log("OK")
     },1000)
  }).then(r => {
     console.log(`then:${r}`)
  }).catch(err => {
     console.log(`catch:${err}`)
  })

2.链式调用

      function wait500(input){
      return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(input + 500)
          },500)
      })
    }
    function wait1000(input){
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(input + 1000)
        },1000)
      })
    }
    const p = new Promise((resolve, reject) => {
      resolve(1)
    })
    p.then(wait500).then(wait1000).then(wait500).then(wait1000).then(res => {
      console.log(`result:${res}`)
    })
    
    注:1.能被链式调用,要返回一个promise对象
        2.使用链式调用,也要用一个promise对象

3.promise.all & promise.race

    //全部执行完毕之后在进行操作
    Promise.all([wait500,wait1000]).then(res => {
      //res返回一个数组[f,f1,f2...]
      console.log('all end' + res)
    })
    //一旦有执行完毕的,立刻操作
    Promise.race([wait500,wait1000]).then(res => {
      console.log('race end' + res)
    })

二、手写Promise

1. promise的框架分析

  • promise的状态:pending,fulfilled,rejected,状态一旦确定无法外部改变
  • 状态流程默认状态为pending,状态流转pending => fulfilled,pending => rejected
  • new Promise的时候的执行器executor()的参数:resolve,reject
  • promise的value保存成功状态的的枚举? - undefined/thenable/promise
  • promise的失败状态值? -reason

2. promise的接口分析

promise一定会有then方法,then接口来源?-两个callback:onFulfilled(value),onRejected(reason)

3.简单手撕一下

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class Promise { // 类
  constructor(executor) { // 构造
    // 默认状态的处理: PENDING
    this.status = PENDING
    // 成功状态的值
    this.value = undefined
    // 失败状态的值
    this.reason = undefined
    
    // 成功状态的回调
    let resolve = value => {
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
      }
    }

    // 失败状态的回调
    let reject = reason => {
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value)
    }

    if (this.status === REJECTED) {
      onRejected(this.reason)
    }
  }
}

const promise = new Promise((resolve, reject) => {
  resolve('成功')
}).then(data => {
  console.log(data)
})

//打印:成功

但是考虑到传入用户传入异步的函数,可以做一下修改。写异步的时候,存在promise在调用then方法的时候并没有成功,而是在pending状态,所以在调用then方法的时候,应该吧回调函数再存一下,依次调用在考虑依次调用的时候,优先考虑队列queue数据结构

// 三个状态:PENDING FULFILLED REJECTED
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    this.onResolvedCallbacks = []
    this.onRejectedCallbacks = []
    let resolve = value => {
      if(this.status === PENDING){
        this.status = FULFILLED
        this.value = value
          // 依次调用对应函数的执行
          (this.onResolvedCallbacks || []).forEach(fn => fn())
      }
    }
    let reject = reason => {
      if(this.status === PENDING){
        this.status = REJECTED
        this.reason = reason
          // 依次调用对应函数的执行
          (this.onRejectedCallbacks || []).forEach(fn => fn())
      }
    }
    try {
      executor(resolve,reject)
    }catch (e) {
      reject(e)
    }
  }
  then(onFulfilled,onRejected){
    if (this.status === FULFILLED) {
      onFulfilled(this.value)
    }

    if (this.status === REJECTED) {
      onRejected(this.reason)
    }
    if(this.status === PENDING){
    //当已经开始执行then函数,但是resolve的函数作为异步函数,还没有执行完毕,所以要把onResolvedCallbacks放在resolve之后来执行,所以保存上这些异步操作,等到resolve之后再进行依次执行
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value)
      })
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason)
      })
    }
  }

}
const promise = new Promise((resolve, reject) => {
  resolve('成功')
}).then(data => {
  console.log(data)
})

当一个同步问题变成异步问题的时候,其实就是在执行的顺序上发生了一些 变化,那么我们就需要开辟一个新的空间来存储异步的内容,用空间解决时间问题