手写Promise

144 阅读4分钟

什么是promise?

Promise是一种异步编程解决方案。

为什么要使用promise?

在谈这个问题之前,先来了解一下回调函数及Generator函数。

js在设计之初是一门单线程的语言,有时候在处理异步请求的时候会发生请求嵌套的情况,这个时候可以用回调,比如下面这个实例:

ajax(url, () => {  // 处理逻辑  
ajax(url, () => {    // 处理逻辑    
ajax(url, () => {    })  })}) 

这样写好像是没有问题的,但是这样写会产生一个很恶心的问题---回调地狱,由于每一次请求都需要上一次请求的执行结果,然后就会发生请求的多层嵌套,这样一直循环嵌套不仅维护起来很困难而且一旦有一个地方发生改变就会牵一发而动全身。

我们该如何解决回调地狱呢?

  • 使用generator函数

function *foo(x) {  
let y = 2 * (yield(x+1))  
let z = yield(y / 3)  
return (x+y+z)}
let it = foo(5)
console.log(it.next()) //{ value: 6, done: false }
console.log(it.next(12)) // { value: 8, done: false }
console.log(it.next(13)) // { value: 42, done: true } true代表程序全部执行完毕

上面函数中的yeild个人感觉有点像return,每次运行到yeild的时候都会返回后面的结果并,然后每次都需要使用next()来运行后面的代码,next()后面的参数则会传入上一次yeild的返回结果。

  • 用generator来写上面的ajax请求代码:

function *fetch() {
  yield ajax(url, () => {})
  yield ajax(url1, () => {})
  yield ajax(url2, () => {})}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()

这样写肯定是没有问题的,下面还可以用promise来写这个代码。

promise的三种状态:

  • 等待中(pending)
  • 完成(resolved)
  • 拒绝(rejected)

promise的状态一经改变不可逆,上面ajax代码可写成下面形式:

new Promise((resolve, reject) => {
ajax(url,() => {
if(success){
resolve('success')
}else{
reject('fail')
}
})
})}).then(res => {
ajax(url,() => {
if(success){
resolve('success')
}else{
reject('fail')
}
})
})
}).then(res => {
ajax(url,() => {
if(success){
resolve('success')
}else{
reject('fail')
}
})
}).catch(err => {})

这里顺带提一下promise.all([])和promise.race([]),这两者其实挺像的,他们都是用来批量执行异步函数的,前者是必须数组里面的方法全部执行成功后才会执行后面的.then方法,后者则只要满足任意一个执行成功就会执行后面的.then方法。

手写promise

// 手写promise// new Promise((resolve, rejecte)=>{// })
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn) {
  const that = this
  that.state = PENDING
  this.value = null
  that.resolvedCallbacks = []
  that.rejectedCallbacks = []
  // 接下来完善resolve和rejecte函数
  function resolve(value){ // new Promise.resolve(1).then()
    if(that.state === PENDING){
      that.state = RESOLVED
      that.value = value
      that.resolvedCallbacks.map(cb => cb(that.value))    }  }
  function reject(value) {
    if (that.state === PENDING) {
      that.state = REJECTED
      that.value = value
      that.rejectedCallbacks.map(cb => cb(that.value))    }  }
  // 完善执行fn
   try {
    fn(resolve,reject)  } catch (error) {
    reject(error)  }}
MyPromise.prototype.then = function(onFulfilled, onRejected){
  const that = this  // 首先判断两个参数的函数类型,因为这两个参数是可选的  // 当参数不是函数类型的时候,我们手动创建一个箭头函数赋值给对应的函数
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => { return v} // 透传
  onRejected  = typeof onRejected === 'function' ? onRejected : r => {throw r}
  if (that.state === PENDING) {    that.resolvedCallbacks.push(onFulfilled)
    that.rejectedCallbacks.push(onRejected)  }
  if(that.state === RESOLVED) {
    onFulfilled(that.value)  }
  if(that.state === REJECTED) {
    onRejected(that.value)
  }}
// 测试
var test = new MyPromise((resolve, reject)=>{
  setTimeout(() => {
    resolve(1)
    console.log(1)
  },1000)})
function test2() {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(2)
      console.log(2) 
   },500)  })}test.then(test2)

实现一个符合promise/A+规范的promise:

// 实现一个符合Promise/A+规范的Promise

const PENDING = 'pending'

const RESOLVED = 'resolved'

const REJECTED = 'rejected'

function MyPromise(fn) {

  const that = this

  that.state = PENDING

  this.value = null

  that.resolvedCallbacks = []

  that.rejectedCallbacks = []

  // 接下来完善resolve和rejecte函数

  function resolve(value){ // new Promise.resolve(1).then()

    if(value instanceof MyPromise) {

      return value.then(resolve, reject)

    }

    setTimeout(() => {

      if(that.state === PENDING){

        that.state = RESOLVED

        that.value = value

        that.resolvedCallbacks.map(cb => cb(that.value))

      }

    },0)

  }  function reject(value) {

    setTimeout(() => {

      if (that.state === PENDING) {

        that.state = REJECTED

        that.value = value

        that.rejectedCallbacks.map(cb => cb(that.value))

      }

    },0)

  }

  // 完善执行fn 

  try {

    fn(resolve,reject)

  } catch (error) {

    reject(error)

  }

}MyPromise.prototype

.then = function(onFulfilled, onRejected){

  const that = this

  // 首先判断两个参数的函数类型,因为这两个参数是可选的

  // 当参数不是函数类型的时候,我们手动创建一个箭头函数赋值给对应的函数

  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => { return v} // 透传

  onRejected  = typeof onRejected === 'function' ? onRejected : r => {throw r}  if (that.state === PENDING) {

    return (promise2 = new MyPromise((resolve, reject) => {

      that.resolvedCallbacks.push(() => {

        try {

          const x = onFulfilled(that.value)

          resolutionProcedure(promise2, x, resolve, reject) // 帮助我们将then函数中的返回结果做一个修改

        } catch (error) {

          reject(error)

        }

      })      that.rejectedCallbacks.push(() => {

        try {

          const x = onRejected(that.value)

          resolutionProcedure(promise2, x, resolve, reject) // 帮助我们将then函数中的返回结果做一个修改

        } catch (error) {

          reject(error)

        }

      })

    }))

    // that.resolvedCallbacks.push(onFulfilled)
    // that.rejectedCallbacks.push(onRejected)  }  if(that.state === RESOLVED) {

    // onFulfilled(that.value)

    return (promise2 = new MyPromise((resolve, reject) => {
      setTimeout(() => {

        try {

          const x = onFulfilled(that.value)

          resolutionProcedure(promise2, x, resolve, reject) // 帮助我们将then函数中的返回结果做一个修改

        } catch (error) {

          reject(error)

        }

      },0)

    }))

  }  if(that.state === REJECTED) {

    // onRejected(that.value)

    return (promise2 = new MyPromise((resolve, reject) => {

      setTimeout(() => {

        try {

          const x = onRejected(that.value)

          resolutionProcedure(promise2, x, resolve, reject) // 帮助我们将then函数中的返回结果做一个修改

        } catch (error) {

          reject(error)

        }

      },0)

    }))  }  function resolutionProcedure(promise2, x, resolve, reject) {

    if(promise2 === x) {

      return reject( new TypeError('Error'))    }    if(x instanceof MyPromise) {

            x.then(function(value) { // promise 链的出处

        resolutionProcedure(promise2, x, resolve, reject)

      },reject)

    }  }}

很少写文章,上面的文章可能有点乱,如果有幸被看到了,希望不吝赐教。