静态函数

Promise.all()

then()函数和catch()函数是Promise原型链中的函数,因此每个Promise的实例可以进行共享,而all()函数是Promise本身的静态函数,用于将多个Promise实例包装成一个新的Promise实例。

  1. const p1 = new Promise((resolve, reject) => {
  2. resolve('success');
  3. }).then(result => result);
  4. const p2 = new Promise((resolve, reject) => {
  5. throw new Error('error');
  6. // 由于p2有自己的catch()函数,所以这个异常会在p2实例内部被消化,并不会继续向外抛到Promise.all()函数中。
  7. }).then(result => result)
  8. .catch(
  9. // p2实例执行完catch()函数后,p2的状态实际是变为fulfilled,只不过它的返回值是Error的信息。
  10. e => e);
  11. Promise.all([p1, p2])
  12. .then(result => console.log(result)) // ['success', Error: error]
  13. .catch(e => console.log(e));

新Promise实例p的状态由p1、p2共同决定,总共会出现以下两种情况:

  • 只有p1、p2全部的状态都变为fulfilled成功状态,p的状态才会变为fulfilled状态,此时p1、p2的返回值组成一个数组,作为p的then()函数的回调函数的参数。
  • 只要p1、p2中有任意一个状态变为rejected失败状态,p的状态就变为rejected状态,此时第一个被reject的实例的返回值会作为p的catch()函数的回调函数的参数。

需要注意的是,如果p1、p2中已经定义了catch()函数,那么当其中一个Promise状态变为rejected时,并不会触发Promise.all()函数的catch()函数。

Promise.race()

Promise.race()函数作用于多个Promise实例上,返回一个新的Promise实例,表示的是如果多个Promise实例中有任何一个实例的状态发生改变,那么这个新实例的状态就随之改变,而最先改变的那个Promise实例的返回值将作为新实例的回调函数的参数。

  1. // 实现一个场景:假如发送一个Ajax请求,在5秒后还没有收到请求成功的响应时,会自动处理成请求失败。
  2. const p1 = ajaxGetPromise('/testUrl');
  3. const p2 = new Promise(function (resolve, reject) {
  4. setTimeout(() => reject(new Error('request timeout')), 5000)
  5. });
  6. const p = Promise.race([p1, p2]);
  7. p.then(res => console.log(res)).catch(e => console.error(e));

Promise.resolve()

Promise.resolve()函数将传入的变量返回为一个状态为fulfilled的Promise实例,等价于在Promise函数体内调用resolve()函数。Promise.resolve()函数执行后,Promise的状态会立即变为fulfilled,然后进入then()函数中做处理。

  1. const p = Promise.resolve('hello');
  2. // 等价于
  3. const p = new Promise(resolve => resolve('hello'));

Promise.reject()

Promise.reject()函数用于返回一个状态为rejected的Promise实例,函数在执行后Promise的状态会立即变为rejected,从而会立即进入catch()函数中做处理,等价于在Promise函数体内调用reject()函数。

  1. const p = Promise.reject('出错了');
  2. // 等价于
  3. const p = new Promise((resolve, reject) => reject('出错了'));

注意点

  • then()函数返回的是一个新Promise实例,因此可以使用链式调用then()函数
  • 在上一轮then()函数内部return的值会作为下一轮then()函数接收的参数值。
  • 在then()函数中不能返回Promise实例本身,否则会出现Promise循环引用的问题,抛出异常。
  • resolve或reject后,后面代码还会执行,建议加return;但后面代码如果还是resolve()函数和reject()函数,则不会执行,因为一个Promise实例只能执行一次状态变更

    1. p().then(res => {
    2. console.log(res)
    3. }).catch(err => {
    4. console.log(err)
    5. })
    6. p1().then(res => {
    7. console.log(res)
    8. }).catch(err => {
    9. console.log(err)
    10. })
    11. p2().then(res => {
    12. console.log(res)
    13. }).catch(err => {
    14. console.log(err)
    15. })
    16. function p() {
    17. return new Promise((resolve, reject) => {
    18. reject('p reject')
    19. console.log('p after') // 这边代码也会执行
    20. setTimeout(() => {
    21. console.log('p setTimeout')
    22. }, 2000)
    23. })
    24. }
    25. function p1() {
    26. return new Promise((resolve, reject) => {
    27. resolve('p1 resolve')
    28. console.log('p1 after') // 这边代码也会执行
    29. })
    30. }
    31. function p2() {
    32. return new Promise((resoleve, reject) => {
    33. return reject(new Error('p2error'))
    34. console.log('p2 after') // 这边代码不会执行
    35. })
    36. }
    37. function p3() {
    38. return new Promise((resoleve, reject) => {
    39. resolve('success1')
    40. reject('error') // 不会执行
    41. resolve('success2') // 不会执行
    42. })
    43. }
  • 重复调用同一个Promise,会一起执行。因为同一个Promise的实例只能有一次状态变换的过程,在状态变换完成后,如果成功会触发所有的then()函数,如果失败会触发所有的catch()函数。

    1. const p = new Promise((resolve, reject) => {
    2. setTimeout(() => {
    3. resolve('success')
    4. }, 1000)
    5. })
    6. const start = Date.now()
    7. // 重复调用实例p的then()函数
    8. p.then((res) => {
    9. // 得到的结果不同也是正常情况,这取决于运行的环境,很可能会相差几毫秒。
    10. console.log(res, Date.now() - start) // success 1004
    11. })
    12. p.then((res) => {
    13. console.log(res, Date.now() - start) // success 1004
    14. })
  • throw和return一个Error的区别:return new Error()是返回一个Error实例,不会被catch捕获;throw new Error()抛出一个Error,才会被catch捕获

    1. Promise.resolve()
    2. .then(() => {
    3. // 返回的是一个Error实例,并将Error实例作为参数传递给第二个then
    4. return new Error('error!!!')
    5. })
    6. .then((res) => {
    7. console.log('then: ', res) // then: Error: error!!!
    8. })
    9. .catch((err) => {
    10. // 不会执行catch
    11. console.log('catch: ', err)
    12. })
  • then()函数接收的参数不是一个规范的函数形式时(即形如(res) => {} ),会发生值穿透现象,即传递的值会被直接忽略掉,继续执行链式调用后续的函数。

    1. Promise.resolve(1)
    2. .then(2) // 参数为2,被忽略
    3. .then(Promise.resolve(3)) // 参数为Promise,不是需要的函数形式,被忽略
    4. .then(console.log) // 1
  • 推荐用catch()函数处理异常,而不要用then()函数的第二个参数去处理:因为then()函数的第二个函数不能捕获第一个函数中抛出的异常,而catch()函数却能捕获到第一个函数中抛出的异常。

    1. Promise.resolve()
    2. .then(function success(res) {
    3. throw new Error('error')
    4. }, function fail1(e) {
    5. // 捕获不到第一个参数抛出的异常
    6. console.error('fail1: ', e)
    7. })
    8. .catch(function fail2(e) {
    9. console.error('fail2: ', e)
    10. })

    封装原生Ajax

    1. // 封装原生get类型Ajax请求
    2. function ajaxGetPromise(url) {
    3. return new Promise((resolve, reject) => {
    4. // 原生Ajax请求操作
    5. const XHR = new XMLHttpRequest()
    6. XHR.open("GET", url)
    7. XHR.onreadystatechange = function () {
    8. //readyState属性表示请求/响应过程的当前活动阶段。
    9. if (XHR.readyState == 4) {
    10. if ((XHR.status >= 200 && XHR.status < 300) || XHR.status == 304) {
    11. try {
    12. //获取数据
    13. let response = JSON.parse(XHR.responseText)
    14. resolve(response)
    15. } catch (e) {
    16. reject(e)
    17. }
    18. } else {
    19. reject(new Error(XHR.statusText))
    20. }
    21. }
    22. }
    23. XHR.responseType = "json"
    24. XHR.setRequestHeader("Accept", "application/json")
    25. XHR.send()
    26. })
    27. }

    实现Promise

    ```javascript const PENDING = ‘pending’ const FULFILLED = ‘fulfilled’ const REJECTED = ‘rejected’

class myPromise {

constructor(executor) { // executor 是一个执行器,进入会立即执行 // 并传入resolve和reject方法 try { executor(this.resolve, this.reject) } catch (error) { // 如果有错误,就直接执行 reject this.reject(error) } }

value = null error = null status = PENDING // 存储成功回调函数 preserveFulCbs = [] // 存储失败回调函数 preserveRejCbs = []

resolve = (value) => { if (this.status === PENDING) { this.status = FULFILLED this.value = value // resolve里面将所有成功的回调拿出来执行 while (this.preserveFulCbs.length) { // Array.shift() 取出数组第一个元素调用,取出后,数组将失去该元素,直到数组为空 this.preserveFulCbs.shift()(value) } } }

reject = (error) => { if (this.status === PENDING) { this.status = REJECTED this.error = error // reject里面将所有失败的回调拿出来执行 while (this.preserveRejCbs.length) { this.preserveRejCbs.shift()(error) } } }

then(onSuccess, onError) { // 如果不传,就使用默认函数 onSuccess = typeof onSuccess === ‘function’ ? onSuccess : value => value onError = typeof onError === ‘function’ ? onError : error => { throw error }

  1. // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
  2. const promise2 = new myPromise((resolve, reject) => {
  3. // 这里的内容在执行器中,会立即执行
  4. if (this.status === FULFILLED) {
  5. // 创建一个微任务等待 promise2 完成初始化
  6. queueMicrotask(() => {
  7. // then 执行的时错误捕获
  8. try {
  9. // 获取成功回调函数的执行结果
  10. const x = onSuccess(this.value)
  11. // 传入 resolvePromise 集中处理
  12. resolvePromise(promise2, x, resolve, reject)
  13. } catch (error) {
  14. reject(error)
  15. }
  16. })
  17. } else if (this.status === REJECTED) {
  18. queueMicrotask(() => {
  19. try {
  20. // 调用失败回调,并且把原因返回
  21. const x = onError(this.error)
  22. // 传入 resolvePromise 集中处理
  23. resolvePromise(promise2, x, resolve, reject)
  24. } catch (error) {
  25. reject(error)
  26. }
  27. })
  28. } else if (this.status === PENDING) {
  29. // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
  30. // 等到执行成功/失败函数的时候再传递
  31. this.preserveFulCbs.push(() => {
  32. queueMicrotask(() => {
  33. try {
  34. // 获取成功回调函数的执行结果
  35. const x = onSuccess(this.value)
  36. // 传入 resolvePromise 集中处理
  37. resolvePromise(promise2, x, resolve, reject)
  38. } catch (error) {
  39. reject(error)
  40. }
  41. })
  42. })
  43. this.preserveRejCbs.push(() => {
  44. queueMicrotask(() => {
  45. try {
  46. // 获取成功回调函数的执行结果
  47. const x = onError(this.value)
  48. // 传入 resolvePromise 集中处理
  49. resolvePromise(promise2, x, resolve, reject)
  50. } catch (error) {
  51. reject(error)
  52. }
  53. })
  54. })
  55. }
  56. })
  57. return promise2

}

// resolve 静态方法 static resolve(parameter) { // 如果传入 myPromise 就直接返回 if (parameter instanceof myPromise) { return parameter }

  1. // 转成常规方式
  2. return new myPromise(resolve => {
  3. resolve(parameter)
  4. })

}

// reject 静态方法 static reject(reason) { return new myPromise((resolve, reject) => { reject(reason) }) } }

function resolvePromise(promise, x, resolve, reject) { // 如果相等了,说明return的是自己,抛出类型错误并返回 if (promise === x) { return reject(new TypeError(‘The promise and the return value are the same’)) }

if (typeof x === ‘object’ || typeof x === ‘function’) { // x 为 null 直接返回,走后面的逻辑会报错 if (x === null) { return resolve(x) }

  1. let then
  2. try {
  3. // 把 x.then 赋值给 then
  4. then = x.then
  5. } catch (error) {
  6. // 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promise
  7. return reject(error)
  8. }
  9. // 如果 then 是函数
  10. if (typeof then === 'function') {
  11. let called = false
  12. try {
  13. then.call(
  14. x, // this 指向 x
  15. // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
  16. y => {
  17. // 如果 resolvePromise 和 rejectPromise 均被调用,
  18. // 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
  19. // 实现这条需要前面加一个变量 called
  20. if (called) return
  21. called = true
  22. resolvePromise(promise, y, resolve, reject)
  23. },
  24. // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
  25. r => {
  26. if (called) return
  27. called = true
  28. reject(r)
  29. })
  30. } catch (error) {
  31. // 如果调用 then 方法抛出了异常 error:
  32. // 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回
  33. if (called) return
  34. // 否则以 error 为据因拒绝 promise
  35. reject(error)
  36. }
  37. } else {
  38. // 如果 then 不是函数,以 x 为参数执行 promise
  39. resolve(x)
  40. }

} else { // 如果 x 不为对象或者函数,以 x 为参数执行 promise resolve(x) } }

let promise = new myPromise((resolve, reject) => { resolve(‘成功’) // reject(‘失败’) // setTimeout(() => { // resolve(‘成功’) // }, 2000) // throw new Error(‘执行器错误’) })

// promise.then(value => { // console.log(‘1’, value) // }, error => { // console.log(‘reject’, error) // })

// promise.then(value => { // console.log(‘2’, value) // }, error => { // console.log(‘reject’, error) // })

// promise.then(value => { // console.log(‘3’, value) // }, error => { // console.log(‘reject’, error) // })

// promise.then(value => { // console.log(1) // console.log(‘resolve’, value) // return new myPromise((resolve, reject) => { // resolve(‘other’) // }) // }).then(value => { // console.log(2) // console.log(‘resolve’, value) // })

// const p1 = promise.then(value => { // console.log(1) // console.log(‘resolve’, value) // return p1 // })

// // 运行的时候会走reject // p1.then(value => { // console.log(2) // console.log(‘resolve’, value) // }, reason => { // console.log(3) // console.log(reason.message) // })

// 第一个then方法中的错误要在第二个then方法中捕获到 // promise.then(value => { // console.log(1) // console.log(‘resolve’, value) // throw new Error(‘then error’) // }, reason => { // console.log(2) // console.log(reason.message) // }).then(value => { // console.log(3) // console.log(value) // }, reason => { // console.log(4) // console.log(reason.message) // })

// promise.then().then().then(value => console.log(value))

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

myPromise.resolve().then(() => { console.log(1) }).then(() => { console.log(2) }).then(() => { console.log(3) }).then(() => { console.log(5) }).then(() => { console.log(6) }) ```