promise原理

148 阅读9分钟

手写

/**
 * state = 'fullfilled' 执行resolve
 * state = 'rejected' 执行reject
 * 
 * state = 'fullfilled'
    * 如果callback 不是函数 --> resolve(this.value)
    * const x = callback(this.value)
    * 如果 x 不是promise对象 --> resolve(x) or reject(x) 和当前状态保持一致
    * 如果 x 是promise对象 --> x.then(resolve, reject)
 */
// new Promise((resolve, reject) => {
//
// })
type Executor = (resolve: Function, reject: Function) => any
// p.then(res => alert(res))
type ThenCB = (res: any) => any
type State = 'pending' | 'success' | 'fail'
type Item = {
  state: State,
  thenCB: ThenCB,
  nextPromiseResolve: Function,
  nextPromiseReject: Function
}

export default class MyPromise {

  _state: State
  _value: any
  list: Item[]

  constructor(executor: Executor) {
    this._state = 'pending'
    this._value = undefined
    this.list = []

    try {
      executor(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
      console.error(error)
    }
  }

  static resolve(value?) {
    // 状态吸收
    // const p6 = MyPromise.reject('err msg p6')
    // const p7 = MyPromise.resolve(p6)
    // p7.catch(err => console.log(err))
    if (likePromise(value)) {
      return value
    }
    
    return new MyPromise(resolve => resolve(value))
  }

  static reject(reason?) {
    return new MyPromise((_, reject) => reject(reason))
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const values = []
      let count = 0

      const add = (i, v) => {
        values[i] = v
        count++
        if (count === promises.length) resolve(values)
      }

      promises.forEach((p, i) => {
        MyPromise.resolve(p).then(
          res => add(i, res),
          rej => reject(rej)
        )
        // 其实可以写成下面这样, 但p就必须是promise对象,不然会出错
        // p.then(
        //   res => add(i, res),
        //   rej => reject(rej)
        // )
      })
    })
  }

  static race(promises: MyPromise[]) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(p => {
        p.then(resolve as ThenCB, reject as ThenCB)
      })
    })
  }

  finally(callback: Function) {
    return this.then(
      res => {
        callback()
        return res
      },
      err => {
        callback()
        throw err
      }
    )
  }

  catch(onRejected) {
    return this.then(null, onRejected)
  }

  then(onResolve?: ThenCB, onReject?: ThenCB) {
    return new MyPromise((resolve, reject) => {
      this.addItem('success', onResolve, resolve, reject)
      this.addItem('fail', onReject, resolve, reject)
      this.runItems() // Promis.resolve().then(() => alert(1))
    })
  }

  runItems() {
    if (this._state === 'pending') {
      return 
    }
    // then的回调函数执行完一定要删除, 防止反复执行
    // const p = Promise.resolve()
    // p.then(() => {console.log(1)})
    // p.then(() => {console.log(2)})
    while (this.list.length) {
      const item = this.list.shift()
      this.runOneItem(item)
    }
  }

  runOneItem(item: Item) {
    const { state, thenCB, nextPromiseReject, nextPromiseResolve } = item;

    if (state !== this._state) {
      return
    }

    pushToTask(() => {
      // 透传
      if (!thenCB) {
        state === 'success' ?
          nextPromiseResolve(this._value) :
          nextPromiseReject(this._value)
        return
      }
      
      try {
        const x = thenCB(this._value)
        // 状态吸收
        // const p1 = Promise.reject(1)
        // const p2 = Promise.resolve(2).then(() => p1)
        likePromise(x) === true
          ? x.then(nextPromiseResolve, nextPromiseReject)
          : nextPromiseResolve(x)
      } catch (e) {
        nextPromiseReject(e)
        console.error(e)
      }
    })
  }

  addItem(state: State, thenCB: ThenCB, nextPromiseResolve: Function, nextPromiseReject: Function) {
    this.list.push({
      state,
      thenCB,
      nextPromiseResolve,
      nextPromiseReject
    })
  }

  _resolve(value?: any) {
    this.setState('success', value)
  }

  _reject(value?: any) {
    this.setState('fail', value)
  }

  setState(state: State, value: any) {
    if (this._state !== 'pending') {
      return // 状态更改后就不能变了
    }

    // 状态吸收
    // const p1 = MyPromise.reject('err msg ...')
    // const p2 = new MyPromise(res => res(p1))
    // p2.catch(err => console.log(err))
    if (likePromise(value)) {
      value.then(this._resolve.bind(this), this._reject.bind(this))
      return
    }

    this._state = state
    this._value = value
    this.runItems()
  }
}

function isNodeEnv() {
  if (globalThis.process && globalThis.process.nextTick) {
    return true
  }
  return false
}

function pushToMicroTask(cb: any) {
  const ob = new MutationObserver(cb)
  const div = document.createElement('div')
  ob.observe(div, {childList: true}) // 监听div, 发生变化就执行cb
  div.innerHTML = '1'
}

export function pushToTask(callback) {
  // node 环境用 nextTick
  if (isNodeEnv()) {
    globalThis.process.nextTick(callback)
    return
  }
  // 浏览器环境且支持 MutationObserver
  if (MutationObserver) {
    pushToMicroTask(callback)
    return
  }

  setTimeout(callback)
}


function isFn(v: any) {
  return typeof v  === 'function'
}

function isObj(v:any) {
  return typeof v === 'object' && v !== null
}

function likePromise(p: any) {
  if (
    (isObj(p) || isFn(p)) && p.then && isFn(p.then)
  ) {
    return true
  }
  return false
}

手写工具函数

实现微队列

  • node 环境使用 process.nextTick
  • 浏览器环境使用 MutationObserver
function isNodeEnv() {
  if (process && process.nextTick) {
    return true
  }
  return false
}

// 观察器的回调函数在微队列中
function pushToMicroTask(cb: any) {
  const ob = new MutationObserver(cb)
  const div = document.createElement('div')
  ob.observe(div, {childList: true}) // 监听div, 发生变化就执行cb
  div.innerHTML = '1'
}

export function pushToTask(callback) {
  // node 环境用 nextTick
  if (isNodeEnv()) {
    process.nextTick(callback)
    return
  }
  // 浏览器环境且支持 MutationObserver
  if (MutationObserver) {
    pushToMicroTask(callback)
    return
  }

  setTimeout(callback)
}

实现promiseLike

判断条件

  • 是一个对象
  • 有then方法

function isFn(v: any) {
  return typeof v  === 'function'
}

function isObj(v:any) {
  return typeof v === 'object' && v !== null
}

function likePromise(p: any) {
  if (
    (isObj(p) || isFn(p)) && p.then && isFn(p.then)
  ) {
    return true
  }
  return false
}

实现Promise.all


  Promise.all = function (arr) {
    return new Promise((resolve, reject) => {
      const values = []
      let count = 0

      const add = (i, v) => {
        values[i] = v
        count++
        if (count === promises.length) resolve(values)
      }

      arr.forEach((p, i) => {
        // 其实可以写成下面这样, 但p就必须是promise对象,不然会出错
        // p.then(
        //   res => add(i, res),
        //   rej => reject(rej)
        // )
        Promise.resolve(p).then(
          res => add(i, res),
          err => reject(err)
        )
      })
    })
  }

实现catch

catch(onRejected) {
    return this.then(null, onRejected)
}

实现finally


  finally(callback: Function) {
    return this.then(
      res => {
        callback()
        return res 
      },
      err => {
        callback()
        throw err
      }
    )
  }

实现Promise.resolve


  static resolve(value?) {
    // 状态吸收
    // const p6 = MyPromise.reject('err msg p6')
    // const p7 = MyPromise.resolve(p6)
    // p7.catch(err => console.log(err))
    if (value instanceof MyPromise) {
      return value
    }

    let resolve, reject
    const p = new MyPromise((reso, reje) => {
      resolve = reso
      reject = reje
    })

    if (likePromise(value)) {
      value.then(resolve, reject)
    }
    else {
      resolve(value)
    }

    return p
  }

实现Promise.reject


  static reject(reason?) {
    return new MyPromise((_, reject) => reject(reason))
  }

async await

return

return undefind

async function fn1() {
    console.log(111)
}

翻译

function fn1() {
  return new Promise(resolve => {
      console.log(111)
      resolve(undefind)
  })
}

return 123

async function fn1() {
  return 123
}

翻译

function fn1() {
  return new Promise(resolve => resolve(123))
}

注意: 不能翻译成这样

function fn1() {
    return Promise.resolve(123)
}

原因如下:


const p1 = Promise.resolve(1)

async function fn() {
  return p1
}

const p2 = fn()

console.log(p1 === p2) // false

const p1 = Promise.resolve(1)

function fn() {
  return new Promise(resolve => resolve(p1))
}

const p2 = fn()

console.log(p1 === p2) // false

const p1 = Promise.resolve(1)

function fn() {
  return Promise.resolve(p1) // 相当于: return p1
}

const p2 = fn()

console.log(p1 === p2) // true

throw error

async function fn1() {
  throw 'err info ...'
}

翻译

function fn1() {
  return Promise.reject('err info ...')
}

也可以这样写, 原因去看Promise.reject源码

function fn1() {
    return new Promise((_, reject) => reject('err info ...'))
}

async中的状态吸收

async function fn1() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(123)
    }, 1000)
  })
}

翻译


function fn1() {
  const p = new Promise((resolve) => {
    setTimeout(() => {
      resolve(123)
    }, 1000)
  })
  
  return new Promise(resolve => resolve(p)) 
}

await

案例1

async function m(){
  const n = await 1;
  console.log(n);
  // return undefind
}

m();
console.log(2);

翻译

function m(){
  return new Promise(resolve => {
      Promise.resolve(1).then(n =>{
          console.log(n)
          resolve(undefind)
      })  
  })
}

m();
console.log(2);

// 答案: 2,1

案例2

  • 注意 setTimeout 前面有一个 await
  • 搞不懂就去看上面的状态吸收, 以及async await
async function async1() {
  console.log(1)
  await async2()
  console.log(2)
}

async function async2() {
  await setTimeout(() => {
    Promise.resolve().then(() => console.log(3))
    console.log(4)
  }, 0)
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

翻译


async function async1() {
  console.log(1)
  async2().then(() => {
    console.log(2)
  })
}

function async2() {
  return new Promise(resolve => {
    const timeId = setTimeout(() => {
      Promise.resolve().then(() => console.log(3))
      console.log(4)
    }, 0)
  
    Promise.resolve(timeId).then(() => resolve(undefined))
  })
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

// 答案: const res = [1, 7, 6, 2, 4, 3]

知识点

// fn1 === fn2
async function fn1() {
  return 1
}
// 相当于
function fn2() {
  return new Promise(resolve => {
    resolve(1)
  })
}
// fn1 === fn2 === fn3 === fn4 === fn5
async function fn1() {
  return await 1
}
// 相当于
async function fn2() {
  return await Promise.resolve(1)
}
// 相当于
async function fn3() {
  const res = await Promise.resolve(1)
  return res
}
// 相当于
function fn4() {
  return new Promise(resolve => {
    Promise.resolve(1).then(res => resolve(res))
  })
}
// 相当于
function fn5() {
  return new Promise(resolve => {
    Promise.resolve(1).then(resolve)
  })
}

例3

async function async1() {
  console.log(1)
  await async2()
  console.log(2)
}
// 和例1唯一的区别: setTimeout 前面没有await
async function async2() {
  setTimeout(() => {
    Promise.resolve().then(() => console.log(3))
    console.log(4)
  }, 0)
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

翻译

async function async1() {
  console.log(1)
  async2().then(() => console.log(2))
}

function async2() {
  return new Promise(resolve => {
    setTimeout(() => {
      Promise.resolve().then(() => console.log(3))
      console.log(4)
    }, 0)

    resolve(undefined)
  })
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

// 答案: const res = [1, 7, 2, 6, 4, 3]

例4

async function async1() {
  console.log(1)
  await async2()
  console.log(2)
}

async function async2() {
  await (async () => {
      await (() => {
        console.log(3)
      })()
      console.log(4)
  })()
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

翻译

async function async1() {
  console.log(1)
  async2().then(() => console.log(2))
}

async function async2() {
  const p = (() => {
    return new Promise(resolve => {
      const res = (() => {
        console.log(3)
      })()
      
      Promise.resolve(res).then(() => {
        console.log(4)
        resolve(undefined)
      })
    })
  })()

  return new Promise(resolve => {
    p.then(() => resolve(undefined))
  })
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

// 答案 const res = [1, 3, 7, 4, 6, 2]

例5

async function async1() {
  console.log(1)
  await async2()
  console.log(2)
}

async function async2() {
  await (async () => {
    Promise.resolve().then(() => console.log(3))
    console.log(4)
  })()
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

翻译

function async1() {
  console.log(1)
  async2().then(() => {
    console.log(2)
    async1Resolve(undefined) // 伪代码
  })
}

async function async2() {
  const p = (() => {
    Promise.resolve().then(() => console.log(3))
    console.log(4)
    resolve(undefined) // 伪代码
  })()

  p.then(() => async2Resolve(undefined))// 伪代码
}

async function async3() {
  Promise.resolve().then(() => {
    console.log(6)
  })
}

async1()
console.log(7)
async3()

// 答案 const res = [1, 4,7,3,6,2]

状态吸收

状态吸收的场景


// 状态吸收1
const p6 = MyPromise.resolve('... p6')
const p7 = MyPromise.reject(p6)
p7.then(err => console.log(err))

// 状态吸收2
const p3 = MyPromise.reject('err msg p3')
const p4 = MyPromise.resolve().then(() => p3)
p4.catch(err=> console.log(err))

// 状态吸收3 
const p1 = MyPromise.reject('err msg ...')
const p2 = new MyPromise(res => res(p1))
p2.catch(err => console.log(err))

第一题

const p1 = new Promise(resolve => resolve(1))
const p2 = new Promise(resolve => resolve(p1))

console.log(p1) 
console.log(p2) 

答案


const p1 = new Promise(resolve => resolve(1))
// resolve(p1)触发状态吸收
// 添加一个微任务 () => p1.then(resolve, reject)
// console.log(p2) 执行完成后才会执行微任务, 所以p2此时的状态为pending
const p2 = new Promise(resolve => resolve(p1))

console.log(p1) // Promise { 1 }
console.log(p2) // Promise { <pending> }

第二题


async function fn1() {
  console.log(1)
  await fn2()
  console.log("AAA")
}

function fn2() {
  return Promise.resolve(2)
}

fn1()

Promise.resolve()
  .then(() => console.log(3))
  .then(() => console.log(4))
  .then(() => console.log(5))

翻译


async function fn1() {
  console.log(1)
  fn2().then(() => console.log("AAA"))
}

function fn2() {
  return Promise.resolve(2)
}

fn1()

Promise.resolve()
  .then(() => console.log(3))
  .then(() => console.log(4))
  .then(() => console.log(5))

答案分析

// 执行: fn2().then(() => console.log("AAA"))
// 添加微任务: () => console.log("AAA")
[
    () => console.log("AAA")
]

// 执行: Promise.resolve().then(() => console.log(3))
// 添加微任务: () => console.log(3)
[
    () => console.log("AAA"),
    () => console.log(3)
]

// 执行 () => console.log("AAA") 没有产生新的微任务
// 执行 () => console.log(3) 
// 添加微任务 () => console.log(4)
[
    () => console.log(4)
]

//执行 () => console.log(4)
//添加微任务 () => console.log(5)
[
    () => console.log(5)
]

// 答案: 1, 'AAA', 3, 4, 5

第三题


async function fn1() {
  console.log(1)
  await fn2()
  console.log("AAA")
}

// 与第二题不同的地方fn2
async function fn2() {
  return Promise.resolve(2)
}

fn1()

Promise.resolve()
  .then(() => console.log(3))
  .then(() => console.log(4))
  .then(() => console.log(5))

翻译


async function fn1() {
  console.log(1)
  fn2().then(() => console.log('AAA'))
}

function fn2() {
  return new Promise((resolve) => {
    const p1 = Promise.resolve(2)
    resolve(p1)
  })
}

fn1()

Promise.resolve()
  .then(() => console.log(3))
  .then(() => console.log(4))
  .then(() => console.log(5))

答案分析

// 同步任务
[
    console.log(1)
]
// 微任务
[
    // 谁生成的该微任务: 
    // resolve(p1)
    () => p1.then(resolve) 
    // 谁生成的该微任务: 
    // Promise.resolve().then(()=>console.log(3))
    () => console.log(3)
    // 谁生成的该微任务: 
    // () => p1.then(resolve) 
    () => resolve()
    // 谁生成的该微任务: 
    // () => console.log(3)
    () => console.log(4)
    // 谁生成的该微任务: 
    // () => resolve()
    () => console.log("AAA")
    // 谁生成的该微任务: 
    // () => console.log(4)
    () => console.log(5)    
]

// 打印结果为: 1, 3, 4, 'AAA', 5

第四题

const p1 = new Promise((resolve) => resolve(1))
const p2 = new Promise((resolve) => resolve(p1))

p2
  .then(() => console.log(1))
  .then(() => console.log(2))
  .then(() => console.log(3))

p1
  .then(() => console.log(4))
  .then(() => console.log(5))
  .then(() => console.log(6))

答案

// 微队列
[
  () => p1.then(resolve),
  () => console.log(4),
  () => resolve(),// 添加者:() => p1.then(resolve),
  () => console.log(5),//添加者:() => console.log(4) 
  () => console.log(1),//添加者:() => resolve()
  () => console.log(6),//添加者:() => console.log(5) 
  () => console.log(2),//添加者:() => console.log(1) 
  () => console.log(3),//添加者:() => console.log(2) 
]

// 4, 5, 1, 6, 2, 3

第五题

Promise.resolve()
  .then(() => {
    console.log(0)
    return Promise.resolve(4)
  })
  .then(res => console.log(res))

Promise.resolve()
  .then(() => console.log(1))
  .then(() => console.log(2))
  .then(() => console.log(3))
  .then(() => console.log(5))

答案

const microTask = [
  () => {
    console.log(0)
    return Promise.resolve(4) // return p4
  },
  () => console.log(1), 
  () => p4.then(resolve), 
  () => console.log(2),
  () => resolve(4),
  () => console.log(3),
  (res) => console.log(res), // res=4
  () => console.log(5),
]

// 答案: 0,1,2,3,4,5

其他面试题

交替执行

Promise.resolve()
  .then(() => console.log(1))
  .then(() => console.log(2))
  .then(() => console.log(3));

Promise.resolve()
  .then(() => console.log(10))
  .then(() => console.log(20))
  .then(() => console.log(30));

Promise.resolve()
  .then(() => console.log(100))
  .then(() => console.log(200))
  .then(() => console.log(300));

答案

//  1
//  10
//  100
//  2
//  20
//  200
//  3
//  30
//  300

catch error

案例1

    Promise.resolve()
    .then(res => {
        console.log('---------- 111')	// √
        throw new Error()
    })
    .catch(err => {
        console.log('---------- 222')	// √
    })
    .then(res => {
        console.log('---------- 333')	// √
    })

案例2

    Promise.resolve()
    .then(res => {
        console.log('---------- 111')	// √
        throw new Error()
    })
    .catch(err => {
        console.log('---------- 222')	// √
    })
    .catch(res => {
        console.log('---------- 333')
    })

事件循环


setTimeout(() => {
  console.log(1)
})

const p = new Promise(resolve => {
  console.log(2)
  resolve(3) 
  Promise.resolve(4).then(console.log)
  console.log(5)
}).then(console.log)
console.log(6)

解析

// 步骤1: 创建 MyPromise 实例,执行executor函数
console.log(2); // 输出: 2

// 步骤2: 调用 resolve(3)
// 注意:此时 Promise 的 then 方法尚未注册

// 步骤3: 创建原生 Promise 并注册 then 回调
// ✅ 将 console.log(4) 加入微任务队列
Promise.resolve(4).then(console.log); 

答案

const res = [2, 5, 6, 4, 3, 1]

const macroTask = [
  () => console.log(1),
]

const microTask = [
  () => console.log(4),
  () => console.log(3),
]

构造函数

new Promise((resolve, reject) => {
  reject(1)
  console.log(2)
  resolve(3)
  console.log(4)
})
  .then(res => console.log(res))
  .catch(err => console.log(err))

try {
  new Promise((resolve, reject) => {
    throw 6
  })
  .then(console.log)
  .catch(err => console.log(8))
} catch (error) {
  console.log(error)
}

// 答案
const res = [2, 4, 1, 8]

const microTask = [
  err => console.log(err),// 1
  err => console.log(8)// 
]

微任务

const promise = new Promise((resolve, reject) => {
    console.log(1);
    resolve();
    console.log(2);
})

promise.then(() => {
    console.log(3);
})

console.log(4);

// 答案: 1,2,4,3

宏任务+微任务

const promise = new Promise((resolve, reject) => {
  console.log(1); 
  setTimeout(()=>{
    console.log(2)
    resolve(null); 
    console.log(3);
  })
})

promise.then(() => {
  console.log(4);
})

console.log(5);

// 答案: 1,5,2,3,4

透传

例1

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 1000)
})
const promise2 = promise1.catch(() => {
  return 2;
})

console.log('promise1', promise1) 
console.log('promise2', promise2) 

setTimeout(() => {
  console.log('promise1', promise1) 
  console.log('promise2', promise2) 
}, 2000)

翻译

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

const promise2 = promise1.then(
  null,
  () => 2
)

console.log('promise1', promise1) 
console.log('promise2', promise2) 

setTimeout(() => {
  console.log('promise1', promise1) 
  console.log('promise2', promise2) 
}, 2000)

// 答案:
// promise1 Promise { <pending> }
// promise2 Promise { <pending> }
// promise1 Promise { 1 }
// promise2 Promise { 1 }

例2

    Promise.resolve()
    .then(res => {
        console.log('---------- 111') // √
    })
    .catch(err => {
        console.log('---------- 222')
    })
    .then(res => {
        console.log('---------- 333')	// √
    })

解析

    Promise.resolve()
    .then(res => console.log('---------- 111'))// √
    .then(null, err => console.log('---------- 222'))
    .then(res => console.log('---------- 333'))// √

例3

const p1 = Promise.reject()
  .then(() => console.log(1))
  .then(() => console.log(2))
  .catch(() => console.log(3));

const p2 = Promise.resolve()
  .then(() => console.log(4))
  .then(() => console.log(5));

解析

// 不会看源码
[
  reject1,
  console.log(4),
  reject2
  console.log(5)
  console.log(3)
]

// 答案: 4, 5, 3