Promise的使用

125 阅读8分钟

首先一个实际例子入手

我们调用一个函数,这个函数中发送网络请求(我们可以用定时器来模拟)

如果发送网络请求成功了,那么告知调用者发送成功,并且将相关数据返回过去;

如果发送网络请求失败了,那么告知调用者发送失败,并且告知错误信息;

function requestData(url,successCallback,failureCallback) {

 setTimeout(()=>{

  if(url==="www.sqda.top") {

   // 发送成功

   successCallback("请求成功")

  } else {

   // 发送失败

   failureCallback("请求失败")

  }

 },2000)

}

requestData("www.sqda.top", (res) => {
 console.log(res)
}, (err) => {
 console.log(err)
})

两秒后打印“请求成功”

什么是Primise?

Promise是一个类,可以翻译成承诺、许诺、期约;

当我们需要给予调用者一个承诺:待会儿我会给你回调数据时,就可以创建一个Promise的对象;

在通过new创建Promise对象时,我们需要传入一个回调函数,我们称之为executor

  • 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject;
  • 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;
  • 当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数;

Promise代码结构

const promise=new Promise((resolve,reject)=>{
  // 调用resolve,那么then传入的回调会被执行
  resolve("success")
  // 调用reject,那么catch传入的回调会被执行
  reject("failure")
})

promise.then(res=>{
  console.log(res); //success
}).catch(err=>{
  console.log(err);
})

上面Promise使用过程,我们可以将它划分成三个状态:

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝;当执行executor中的代码时,处于该状态;
  • 已兑现(fulfilled): 意味着操作成功完成;执行了resolve时,处于该状态;
  • 已拒绝(rejected): 意味着操作失败;执行了reject时,处于该状态;

这里需要注意:一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的

  • 在我们调用resolve的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成兑现(fulfilled);
  • 在之后我们去调用reject时,已经不会有任何的响应了(并不是这行代码不会执行,而是无法改变Promise状态);

resolve不同值的区别

 ``* resolve(参数)
 ``* 1> 普通的值或者对象 pending -> fulfilled
 ``* 2> 传入一个Promise
 ``*  那么当前的Promise的状态会由传入的Promise来决定
 ``*  相当于状态进行了移交
 ``* 3> 传入一个对象, 并且这个对象有实现then方法(并且这个对象是实现了thenable接口)
 ``*  那么也会执行该then方法, 并且又该then方法决定后续状态

//1.
new Promise((resolve, reject) => {
  resolve("success");
}).then((res) => {
  console.log("res:", res);
});
//res: success

//2.
const promise = new Promise((resolve, reject) => {
  resolve("success");
})

promise.then(res => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(111111)
    }, 3000)
  })
}).then(res => {
  console.log("res:", res)
})
//res: 111111

//3.
promise.then(res => {
  return {
    then: function(resolve, reject) {
      resolve(222222)
    }
  }
}).then(res => {
  console.log("res:", res)
})
//res: 222222

Promise的对象方法

then方法多次调用

当Promise的状态变成fulfilled的时候,这些回调函数都会被执行;

const promise = new Promise((resolve, reject) => {
  resolve("success");
})

promise.then(res => {
  console.log(res,111);
})

promise.then(res => {
  console.log(res,222);
})

promise.then(res => {
  console.log(res,333);
})
//success 111
//success 222
//success 333

then方法----返回值

  • hen方法本身是有返回值的,它的返回值是一个Promise,所以我们可以进行如下的链式调用

  • Promise有三种状态,那么这个Promise处于什么状态呢

    当then方法中的回调函数本身在执行的时候,那么它处于pending状态;

    p当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;

    1. 返回一个普通值
    2. 返回一个Promise
    3. 返回一个thenable值
  • 当then方法抛出一个异常时,那么它处于reject状态;

catch方法–多次调用

和then一个意思

const promise = new Promise((resolve, reject) => {
  reject("fail");
})

promise.catch(res => {
  console.log(res,111);
})

promise.catch(res => {
  console.log(res,222);
})

promise.catch(res => {
  console.log(res,333);
})
//fail 111
//fail 222
//fail 333

catch方法–返回值

const promise = new Promise((resolve, reject) => {
  reject("fail");
})

promise.catch(res => {
  console.log(res,111);
}).catch(err=>{
  console.log(err,222);
}).then(res=>{
  console.log(res,333);
})
//fail 111
//undefined 333

为什么不会打印222那行代码呢?

因为catch传入的回调在执行完后,默认状态依然会是fulfilled的;

如果我们希望继续执行catch,那么需要抛出一个异常

const promise = new Promise((resolve, reject) => {
  reject("fail");
})

promise.catch(res => {
  console.log(res,111);
  throw new Error("error message")
}).catch(err=>{
  console.log(err,222);
}).then(res=>{
  console.log(res,333);
})
// fail 111
// Error: error message
// ..... 222
// undefined 333

finally方法

finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。

const promise = new Promise((resolve, reject) => {
  // resolve("resolve message")
  reject("reject message")
})
 
promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
}).finally(() => {
  console.log("finally code execute")
})
// err: reject message
// finally code execute

Promise类方法

resolve

const promise = Promise.resolve({ name: "why" })
// 相当于
const promise2 = new Promise((resolve, reject) => {
  resolve({ name: "why" })
})
promise2.then(res=>{
  console.log(res);
})
//{ name: 'why' }

reject

const promise = Promise.reject(new Promise(() => {}))
 
promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
})

all

它的作用是将多个Promise包裹在一起形成一个新的Promise;

新的Promise状态由包裹的所有Promise共同决定:

1.当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;

2.当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})
 
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(22222)
  }, 2000);
})
 
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})
 
// 需求: 所有的Promise都变成fulfilled时, 再拿到结果
// 意外: 在拿到所有结果之前, 有一个promise变成了rejected, 那么整个promise是rejected
Promise.all([p2, p1, p3, "aaaa"]).then(res => {
  console.log(res)
}).catch(err => {
  console.log("err:", err)
})
//[ 22222, 11111, 33333, 'aaaa' ]

allSettled

该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态;

p并且这个Promise的结果一定是fulfilled的;

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})
 
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})
 
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})
 
// allSettled
Promise.allSettled([p1, p2, p3]).then(res => {
  console.log(res)
}).catch(err => {
  console.log(err)
})
// [
//   { status: 'fulfilled', value: 11111 },
//   { status: 'rejected', reason: 22222 },
//   { status: 'fulfilled', value: 33333 }
// ]

race

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 3000);
})
 
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 500);
})
 
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 1000);
})
 
// race: 竞技/竞赛
// 只要有一个Promise变成fulfilled状态, 那么就结束
Promise.race([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
})
//err: 22222

any

  • any方法会等到一个fulfilled状态,才会决定新Promise的状态;
  • 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态;
  • 如果所有的Promise都是reject的,那么会报一个AggregateError的错误。
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve(11111)
    reject(1111)
  }, 1000);
})
 
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 500);
})
 
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve(33333)
    reject(3333)
  }, 3000);
})
 
// any方法
Promise.any([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err.errors)
})
//err: [ 1111, 22222, 3333 ]

手写Promise

// ES6 ES2015
// https://promisesaplus.com/
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
 
// 工具函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
  try {
    const result = execFn(value)
    resolve(result)
  } catch(err) {
    reject(err)
  }
}
 
class HYPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []
 
    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 添加微任务
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          this.onFulfilledFns.forEach(fn => {
            fn(this.value)
          })
        });
      }
    }
 
    const reject = (reason) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 添加微任务
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        })
      }
    }
 
    try {
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
 
  then(onFulfilled, onRejected) {
    const defaultOnRejected = err => { throw err }
    onRejected = onRejected || defaultOnRejected
 
    const defaultOnFulfilled = value => { return value }
    onFulfilled = onFulfilled || defaultOnFulfilled
 
    return new HYPromise((resolve, reject) => {
      // 1.如果在then调用的时候, 状态已经确定下来
      if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
      }
      if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
        execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
      }
 
      // 2.将成功回调和失败的回调放到数组中
      if (this.status === PROMISE_STATUS_PENDING) {
        if (onFulfilled) this.onFulfilledFns.push(() => {
          execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
        })
        if (onRejected) this.onRejectedFns.push(() => {
          execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
        })
      }
    })
  }
 
  catch(onRejected) {
    return this.then(undefined, onRejected)
  }
 
  finally(onFinally) {
    this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }
 
  static resolve(value) {
    return new HYPromise((resolve) => resolve(value))
  }
 
  static reject(reason) {
    return new HYPromise((resolve, reject) => reject(reason))
  }
 
  static all(promises) {
    // 问题关键: 什么时候要执行resolve, 什么时候要执行reject
    return new HYPromise((resolve, reject) => {
      const values = []
      promises.forEach(promise => {
        promise.then(res => {
          values.push(res)
          if (values.length === promises.length) {
            resolve(values)
          }
        }, err => {
          reject(err)
        })
      })
    })
  }
 
  static allSettled(promises) {
    return new HYPromise((resolve) => {
      const results = []
      promises.forEach(promise => {
        promise.then(res => {
          results.push({ status: PROMISE_STATUS_FULFILLED, value: res})
          if (results.length === promises.length) {
            resolve(results)
          }
        }, err => {
          results.push({ status: PROMISE_STATUS_REJECTED, value: err})
          if (results.length === promises.length) {
            resolve(results)
          }
        })
      })
    })
  }
 
  static race(promises) {
    return new HYPromise((resolve, reject) => {
      promises.forEach(promise => {
        // promise.then(res => {
        //   resolve(res)
        // }, err => {
        //   reject(err)
        // })
        promise.then(resolve, reject)
      })
    })
  } 
 
  static any(promises) {
    // resolve必须等到有一个成功的结果
    // reject所有的都失败才执行reject
    const reasons = []
    return new HYPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, err => {
          reasons.push(err)
          if (reasons.length === promises.length) {
            reject(new AggregateError(reasons))
          }
        })
      })
    })
  }
}
 
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => { reject(1111) }, 3000)
})
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => { reject(2222) }, 2000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => { reject(3333) }, 3000)
})
 
 
// HYPromise.race([p1, p2, p3]).then(res => {
//   console.log("res:", res)
// }).catch(err => {
//   console.log("err:", err)
// })
 
HYPromise.any([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err.errors)
})