Promise超详细(含手撕)

目录

一、promise的操作

0.初体验-promise的使用

(1)抽奖案列,用一下promise

(2)promise进行文件操作:

(3)使用promise发送ajax请求

1.Promise封装fs读取文件操作 

2.Promise封装原生ajax GET请求

3.Promise实例对象的两个属性

(1)状态属性PromiseState

(2)结果值属性PromiseResult

4.Promise的工作流程

5.Promise的API

(1)then和catch

(2)Promise.resolve (value)

(3)Promise.reject(reason)

(4)Promise.all([p1,p2,p3])

二、一些关键问题

1.如何修改promise对象的状态

2.能否执行多个回调

3.改变promise状态和指定回调的区别

4..then(),.catch()返回的新 promise 的结果和状态由什么决定

5.串联多个任务(链式调用)

6.异常穿透

7.中断Promise链

三、手撕Promise

1.搭建整体结构

2.resolve和reject的实现

3.throw抛出错误改变状态

4.状态一旦改变就不能再变

5.then方法的初步封装

5.异步任务回调的执行

6.执行多个then的回调

7.同步任务then方法的返回结果(难点)

8.异步任务then方法的返回结果(难点)

9.then方法中封装重复代码

11.Promise.resolve方法封装

12.Promise.reject方法封装

13.Promise.all方法封装(难点)

14.Promise.race方法封装

15.细节:then方法的回调是异步执行的

16.class版本

四、async函数和await表达式(难点)

1.async函数

2.await表达式

3.async和await结合


一、promise的操作

0.初体验-promise的使用
(1)抽奖案列,用一下promise

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>初体验</title>
</head>

<body>
  <div class="container">
    <h2>Promise 初体验</h2>
    <button class="btn btn-primary" id="btn">点击抽奖</button>
  </div>
</body>
<script>
  function rand(m, n) {
    return Math.ceil(Math.random() * (n - m + 1)) + m - 1
  }
  const btn = document.querySelector('#btn');
  btn.addEventListener('click', function () {

    // setTimeout(() => {
    //   let n = rand(1, 100);
    //   if (n <= 30) {
    //     alert('您未中奖')
    //   } else {
    //     alert('恭喜您中奖了')
    //   }
    // }, 1000)

    // promise里面传一个回调函数
    // 参数为resolve--解决--函数类型数据和reject--拒绝--函数类型数据 
    // 
    const p = new Promise((resolve, reject) => {
      // 异步操作放到回调函数里
      setTimeout(() => {
        let n = rand(1, 100);
        if (n <= 30) {
          // 成功调用这个函数
          resolve(n)         //将promise状态设置为成功
        } else {
          // 失败调用这个函数
          reject(n)        //将promise状态设置为失败
        }
        console.log(n);

      }, 1000)
    })
    // 状态成功执行第一个回调函数,失败执行第二个回调函数
    p.then((value) => {
      alert('恭喜您中奖了,中将号码为' + value)
    }, (reason) => {
      alert('您未中奖,号码为' + reason)
    })
  })
</script>
(2)promise进行文件操作:
const { log } = require('console')
const fs = require('fs')
// 回调形式
// fs.readFile('./resource/context.txt', (err, data) => {
//   if (err) throw error
//   console.log(data.toString())
// }),
const p = new Promise((resolve, reject) => {
  fs.readFile('./resource/context.txt', (err, data) => {
    // 如果失败调用 reject函数 并传入err参数
    if (err) reject(err)
    // 如果成功调用 resolve函数 并传入data参数
    resolve(data)
  })
})
p.then((value) => {
  console.log(value.toString())
}, (err) => {
  console.log(err)
})
(3)使用promise发送ajax请求

要熟练掌握发送原生ajax请求


<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div class="container"></div>
  <h2>Promise封装ajax</h2>
  <button class="btn btn-primary" id="btn">发送ajax请求</button>
  </div>
</body>
<script>
  const btn = document.querySelector('#btn')
  btn.addEventListener('click', function () {
    const p = new Promise((resolve, reject) => {
      // 1.创建对象
      const xhr = new XMLHttpRequest()
      // 2.初始化
      xhr.open('GET', 'https://www.baidu.com/')
      // 3.发送请求
      xhr.send()
      // 4.处理响应结果
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve(xhr.response)
          } else {
            reject(xhr.status)
          }
        }
      }
    })
    p.then(response => {
      console.log(response)
    }, status => {
      console.log(status)
    })
  })

</script>
1.Promise封装fs读取文件操作 

 封装一个函数myReadFile 读取文件内容

 参数:path 文件路径

 返回:promise对象

function myReadFile(path) {
  return new Promise((resolve, reject) => {
    require('fs').readFile(path, (err, data) => {
      if (err) reject(err)
      resolve(data)
    })
  })
}
// 返回的是一个promise对象所以可以then
myReadFile('./resource/context.txt').then(value => {
  console.log(value.toString())
}, reason => {
  console.log(reason)
})

util.promisify()函数封装读取文件操作

// 引入util
const util = require('util')
// 引入fs
const fs = require('fs');
// 相当于把fs.readFile函数转为了promise风格
// 前面的参数你自己传,后面的回调函数代码固定,自动给你写好了
// 是err优先,并且参数都给你传好了 
// 所以能转成promise风格的函数也不多
// 函数返回promise
let myReadFile = util.promisify(fs.readFile);
myReadFile('./resource/context.txt').then(value => {
  console.log(value.toString())
}, reason => {
  console.log(reason)
})
2.Promise封装原生ajax GET请求
<script>
  function sendAjax(url) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      xhr.open('GET', url)
      xhr.send()
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve(xhr.response)
          } else {
            reject(xhr.status)
          }
        }
      }
    })
  }
  sendAjax('http://api.apiopen.top/getJok').then(value => {
    console.log(value.toString())
  }, reason => {
    console.log(reason)
  })
</script>
3.Promise实例对象的两个属性
(1)状态属性PromiseState

        初始PromiseState的值为pending未决定的,之后成功就是pending变为resolved(或fullfilled),失败就变成了rejected。且一个promise对象只能改变一次,不可能从resolved变到rejected,也不可能从rejected变为resolved。

(2)结果值属性PromiseResult

保存着异步任务成功或失败的结果,只有resolve和reject接收到的值决定它的值。

4.Promise的工作流程

5.Promise的API
(1)then和catch

(2)Promise.resolve (value)

resolve属于函数对象而不是实例对象

value: 成功的数据或 promise 对象
说明 : 返回一个成功 / 失败的 promise 对象
    <script>
        //
        let p1 = Promise.resolve(521);
        //如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
        //如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
        let p2 = Promise.resolve(new Promise((resolve, reject) => {
            // resolve('OK');
            reject('Error');
        }));
        // console.log(p2);
        p2.catch(reason => {
            console.log(reason);
        })
    </script>
(3)Promise.reject(reason)

reason: 失败的原因

说明 : 返回一个失败的 promise 对象

无论value传入什么值,返回的都是失败的promise对象

(4)Promise.all([p1,p2,p3])

传入一个数组,若p1、p2、p3都是一个成功的promise对象则函数返回一个新的成功的promise对象,且属性值为p1、p2、p3属性值组成的数组。只要有一个失败返回的就是一个失败的promise对象,属性值为失败的那个promise的属性值。若有多个失败呢?只会有一个失败,后面的不执行。

成功:

  <script>
    let p1 = new Promise((resolve, reject) => {
      resolve('OK')
    })
    let p2 = Promise.resolve('yes')
    let p3 = Promise.resolve('year')
    console.log(Promise.all([p1, p2, p3]))
  </script>

失败:

  <script>
    let p1 = new Promise((resolve, reject) => {
      resolve('OK')
    })
    let p2 = Promise.reject('err')
    let p3 = Promise.reject('shibai')
    console.log(Promise.all([p1, p2, p3]))
  </script>

(5)Promise.race([p1,p2,p3])

返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态,race赛跑的意识,相当于数组里的promise进行赛跑,谁的状态先改变,race函数的返回结果状态和属性值就看它。
  <script>
    let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('OK')
      }, 1000)

    })
    let p2 = Promise.reject('err')
    let p3 = Promise.reject('shibai')
    console.log(Promise.race([p1, p2, p3]))
  </script>

二、一些关键问题

1.如何修改promise对象的状态
(1) resolve(value): 如果当前是 pending 就会变为 resolved
(2) reject(reason): 如果当前是 pending 就会变为 rejected
(3) 抛出异常 : 如果当前是 pending 就会变为 rejected
2.能否执行多个回调
promise 改变为对应状态时都会调用
  <script>
    let p = new Promise((resolve, reject) => {
      resolve('ok')
    })
    p.then(value => {
      console.log('执行1')
    })
    p.then(value => {
      console.log('执行2')
    })
    // 结果俩个都执行
  </script>
3.改变promise状态和指定回调的区别

指定回调就是then,指定和执行不一样。

     都有可能, 正常情况下是先指定回调再改变状态 , 但也可以先改状态再指定回调
  如何先改状态再指定回调 ?
① 在执行器中直接调用 resolve()/reject()
② 延迟更长时间才调用 then()
         什么时候才能得到数据 ?
① 如果先指定的回调 , 那当状态发生改变时 , 回调函数就会调用 , 得到数据
② 如果先改变的状态 , 那当指定回调时 , 回调函数就会调用 , 得到数据

先指定回调再改变状态再执行回调函数


 <script>
  let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('ok')
      }, 1000)
    })
    p.then(value => {
      console.log('执行1')
    }, reason => {

    })

  </script>
4..then(),.catch()返回的新 promise 的结果和状态由什么决定
简单表达 : then() 指定的回调函数执行的结果决定
详细表达 :
(1)如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
(2) 如果返回的是非 promise 的任意值 , promise 变为 resolved, value 为返回的值
(3)如果返回的是另一个新 promise, promise 的结果就会成为新 promise 的结果
  let p = new Promise((resolve, reject) => {
      resolve('ok')
    })
    let result = p.then(value => {
      // throw 'Error'
      // return 520
      return new Promise((resolve, reject) => {
        resolve('success')
      })
    }, reason => {

    })
    console.log(result)

5.串联多个任务(链式调用)
(1)promise then() 返回一个新的 promise, 可以开成 then() 的链式调用
(2)通过 then 的链式调用串连多个同步 / 异步任务
  let p = new Promise((resolve, reject) => {
      resolve('ok')
    })
    let result = p.then(value => {
      // throw 'Error'
      // return 520
      return new Promise((resolve, reject) => {
        resolve('success')
      })
    }).then(value => {
      console.log(value)  //上一个是新promise对象调用then,value为success 
    }).then(value => {
      console.log(value) //输出为undefined,因为上一个then返回新的promise,没有返回值,所以没属性值,根据规则是状态是成功
    })
    console.log(result)
6.异常穿透
        当使用 promise then 链式调用时 , 可以在最后指定失败的回调, 前面任何操作出了异常, 都会传到最后失败的回调中处理。
   let p = new Promise((resolve, reject) => {
      resolve('ok')
    })
    let result = p.then(value => {
      // throw 'Error'
      // return 520
      return new Promise((resolve, reject) => {
        resolve('success')
      })
    }).then(value => {
      console.log(111)
      throw 'erroe'
    }).then(value => {
      console.log(222)
    }).then(value => {
      console.log(333)
    }).catch(reason => {
      console.warn(reason)
    })

上面出现的错误会在最后的catch里被处理

7.中断Promise链
当使用 promise then 链式调用时 , 在中间中断 , 不再调用后面的回调函数,
只有一种办法在回调函数中返回一个 pendding 状态的 promise 对象,只有是pendding状态才不会执行下面的任何代码。
  let p = new Promise((resolve, reject) => {
      resolve('ok')
    })
    let result = p.then(value => {
      // throw 'Error'
      // return 520
      return new Promise((resolve, reject) => {
        resolve('success')
      })
    }).then(value => {
      console.log(111)
    }).then(value => {
      console.log(222)
      // return new Promise((resolve, reject) => { })
      return new Promise(() => { })
    }).then(value => {
      console.log(333)
    }).catch(reason => {
      console.warn(reason)
    })

三、手撕Promise

1.搭建整体结构

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./promise.js"></script>
</head>

<body>
  <script>
    let p = new Promise((resolve, reject) => {
      resolve('OK')
    });
    p.then(value => {
      console.log(value)
    }, reason => {
      console.log(reason)
    })
  </script>
</body>

</html>

在index.html中引入promise.js,并在其中设置两个函数,去覆盖原来的Promise和then,并且使用构造函数时要同步调用executor

function Promise(executor) {
  // resolve函数
  function resolve(data) {

  }
  // reject函数
  function reject(data) {

  }
  // 同步调用函数执行器
  executor(resolve, reject)
}
Promise.prototype.then = function (onResolved, onRejected) {

}
2.resolve和reject的实现

注意里面resolve函数this指向window的两种解决办法

function Promise(executor) {
  this.promiseState = 'pending'
  this.promiseResult = null
  const self = this
  // resolve函数
  //如果写成function,里面的this指向为window,所以写成箭头函数
  // 或者在外面用self保存好this
  resolve = (data) => {
    // 1.功能:修改对象的状态promiseState
    this.promiseState = 'fulfilled'
    // 2.设置对象结果值(promiseResult)
    this.promiseResult = data
  }
  // reject函数
  function reject(data) {
    // 1.功能:修改对象的状态promiseState
    self.promiseState = 'rejected'
    // 2.设置对象结果值(promiseResult)
    self.promiseResult = data
  }
  // 同步调用函数执行器
  executor(resolve, reject)
}
Promise.prototype.then = function (onResolved, onRejected) {

}
3.throw抛出错误改变状态

throw抛出错误,用catch接到仔调用reject改变promise状态和属性值

  try {
    // 同步调用函数执行器
    executor(resolve, reject)
  } catch (e) {
    // 修改promise状态为失败
    reject(e)
  }
4.状态一旦改变就不能再变

只需在里面加个promiseState的判断

  // resolve函数
  //如果写成function,里面的this指向为window,所以写成箭头函数
  // 或者在外面用self保存好this
  resolve = (data) => {
    // 判断状态,只有pending的时候才能改变状态
    // 即状态只能改变一次
    if (this.promiseState !== 'pending') return
    // 1.功能:修改对象的状态promiseState
    this.promiseState = 'fulfilled'
    // 2.设置对象结果值(promiseResult)
    this.promiseResult = data
  }
  // reject函数
  function reject(data) {
    if (self.promiseState !== 'pending') return
    // 1.功能:修改对象的状态promiseState
    self.promiseState = 'rejected'
    // 2.设置对象结果值(promiseResult)
    self.promiseResult = data
  }
5.then方法的初步封装

在then方法里加上两个判断并调用函数

  if (this.promiseState === 'fulfilled') {
    onResolved(this.promiseResult)
  }
  if (this.promiseState === 'rejected') {
    onRejected(this.promiseResult)
  }
5.异步任务回调的执行

        异步执行,状态还没有改变,就去执行then了,而因为then没有对状态为pending的处理,所以执行不成功。我们需要在then加上对pending状态的处理。把函数保存到自己的callback上,然后在状态改变之后调用。

function Promise(executor) {
  this.promiseState = 'pending'
  this.promiseResult = null
  this.callback = {}
  const self = this
  // resolve函数
  //如果写成function,里面的this指向为window,所以写成箭头函数
  // 或者在外面用self保存好this
  resolve = (data) => {
    // 判断状态,只有pending的时候才能改变状态
    // 即状态只能改变一次
    if (this.promiseState !== 'pending') return
    // 1.功能:修改对象的状态promiseState
    this.promiseState = 'fulfilled'
    // 2.设置对象结果值(promiseResult)
    this.promiseResult = data
    // 状态改变了再去执行then的回调函数
    if (this.callback.onResolved) {
      this.callback.onResolved(data)
    }

  }
  // reject函数
  function reject(data) {
    if (self.promiseState !== 'pending') return
    // 1.功能:修改对象的状态promiseState
    self.promiseState = 'rejected'
    // 2.设置对象结果值(promiseResult)
    self.promiseResult = data
    // 状态改变了再去执行then的回调函数
    if (self.callback.onRejected) {
      self.callback.onRejected(data)
    }
  }


  try {
    // 同步调用函数执行器
    executor(resolve, reject)
  } catch (e) {
    // 修改promise状态为失败
    reject(e)
  }

}
Promise.prototype.then = function (onResolved, onRejected) {
  // 分别判断,调用这两个函数
  if (this.promiseState === 'fulfilled') {
    onResolved(this.promiseResult)
  }
  if (this.promiseState === 'rejected') {
    onRejected(this.promiseResult)
  }
  if (this.promiseState === 'pending') {
    // 要把回调函数保存到自身上。
    this.callback = {
      onResolved: onResolved,
      onRejected: onRejected
    }
  }
}
6.执行多个then的回调

        当在异步情况下执行多个then函数时,上面callback的保存方法会出现覆盖的情况,所以我们要把它改为数组,并且在状态改变后要用遍历的方式去调用

function Promise(executor) {
  this.promiseState = 'pending'
  this.promiseResult = null
  this.callbacks = []
  const self = this
  // resolve函数
  //如果写成function,里面的this指向为window,所以写成箭头函数
  // 或者在外面用self保存好this
  resolve = (data) => {
    // 判断状态,只有pending的时候才能改变状态
    // 即状态只能改变一次
    if (this.promiseState !== 'pending') return
    // 1.功能:修改对象的状态promiseState
    this.promiseState = 'fulfilled'
    // 2.设置对象结果值(promiseResult)
    this.promiseResult = data
    // 状态改变了再去执行then的回调函数
    this.callbacks.forEach((item) => {
      item.onResolved(data)
    })
  }
  // reject函数
  function reject(data) {
    if (self.promiseState !== 'pending') return
    // 1.功能:修改对象的状态promiseState
    self.promiseState = 'rejected'
    // 2.设置对象结果值(promiseResult)
    self.promiseResult = data
    // 状态改变了再去执行then的回调函数
    self.callbacks.forEach((item) => {
      item.onRejected(data)
    })
  }


  try {
    // 同步调用函数执行器
    executor(resolve, reject)
  } catch (e) {
    // 修改promise状态为失败
    reject(e)
  }

}
Promise.prototype.then = function (onResolved, onRejected) {
  // 分别判断,调用这两个函数
  if (this.promiseState === 'fulfilled') {
    onResolved(this.promiseResult)
  }
  if (this.promiseState === 'rejected') {
    onRejected(this.promiseResult)
  }
  if (this.promiseState === 'pending') {
    // 要把回调函数保存到自身上。
    this.callbacks.push({
      onResolved: onResolved,
      onRejected: onRejected
    })
  }
}
7.同步任务then方法的返回结果(难点)

实现then的返回值,它的值是一个Promise,其状态和结果值与回调函数返回的结果有关。如果回调函数返回的是promise,则then返回的promise的结果和状态和他一样。如果回调函数返回的不是promise,则then返回的promise的状态为成功,值是回调函数返回的值(没有就是undefined)。如果抛出异常,状态是异常,值为抛出的值。

 <script>
    let p = new Promise((resolve, reject) => {
      resolve('chenggong')
      // setTimeout(() => {
      //   reject('shibai')
      // }, 1000)

      // throw 'shibai'
    });
    // console.log(p)
    const res = p.then(value => {
      // console.log(value)
      // 实现then的返回值,如果回调函数返回的是Promise则状态和结果与Promise有关
      // return 'hello Promise'
      return new Promise((resolve, reject) => {
        reject('shibai')
      })
      // 抛出异常
      // throw 'Fail'
    }, reason => {
      console.log(reason)
    })
    // p.then(value => {
    //   alert(value)
    // }, reason => {
    //   alert(reason)
    // })
    // console.log(p)
    console.log(res)
  </script>


Promise.prototype.then = function (onResolved, onRejected) {
  // then的返回值是一个promise
  return new Promise((resolve, reject) => {
    // 分别判断,调用这两个函数
    if (this.promiseState === 'fulfilled') {
      try {
        // 获取回调函数的执行结果
        let result = onResolved(this.promiseResult)
        if (result instanceof Promise) {
          // 如果是Promise对象,修改当前要返回的Promise的状态和值
          result.then(value => {
            resolve(value)
          }, reason => {
            reject(reason)
          })
        } else {
          // 结果对象状态为成功
          resolve(result)
        }
      } catch (e) {
        reject(e)
      }
    }
    if (this.promiseState === 'rejected') {
      onRejected(this.promiseResult)
    }
    if (this.promiseState === 'pending') {
      // 要把回调函数保存到自身上。
      this.callbacks.push({
        onResolved: onResolved,
        onRejected: onRejected
      })
    }
  })

}
8.异步任务then方法的返回结果(难点)

和同步差不多,关键是改callbacks里的函数

  <script>
    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('chenggong ')
      }, 1000)
    });
    const res = p.then(value => {
      throw 'Fail'
    }, reason => {
      console.log(reason)
    })
    console.log(res)
  </script>



   if (this.promiseState === 'pending') {
      // 要把回调函数保存到自身上。
      this.callbacks.push({
        onResolved: function () {
          try {
            // 执行成功的回调函数
            let result = onResolved(self.promiseResult)
            // 判断
            if (result instanceof Promise) {
              result.then(value => {
                resolve(value)
              }, reason => {
                reject(reason)
              })
            } else {
              resolve(result)
            }
          } catch (e) {
            reject(e)
          }

        },
        onRejected: function () {
          let result = onRejected(self.promiseResult)
          try {
            // 判断
            if (result instanceof Promise) {
              result.then(value => {
                resolve(value)
              }, reason => {
                reject(reason)
              })
            } else {
              resolve(result)
            }
          } catch (e) {
            reject(e)
          }
        }
      })
    }
  })
9.then方法中封装重复代码

把判断是不是Promise的代码来修改then返回的promise的状态和值的那段代码进行封装

Promise.prototype.then = function (onResolved, onRejected) {
  const self = this
  // then的返回值是一个promise
  return new Promise((resolve, reject) => {
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.promiseResult)
        if (result instanceof Promise) {
          // 如果是Promise对象,修改当前要返回的Promise的状态和值
          result.then(value => {
            resolve(value)
          }, reason => {
            reject(reason)
          })
        } else {
          // 结果对象状态为成功
          resolve(result)
        }
      } catch (e) {
        reject(e)
      }
    }
    // 分别判断,调用这两个函数
    if (this.promiseState === 'fulfilled') {
      callback(onResolved)
    }
    if (this.promiseState === 'rejected') {
      callback(onRejected)
    }
    if (this.promiseState === 'pending') {
      // 要把回调函数保存到自身上。
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })

}

10.catch方法封装,异常穿透(难点)

下面那段代码写进then方法里,如果then没有传成功或失败的回调函数,就默认给你创建一个

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

//写在then方法里

 if (typeof onRejected !== 'function') {
    onRejected = reason => {
      throw reason
    }
  }
  if (typeof onResolved !== 'function') {
    onResolved = value => value
  }
11.Promise.resolve方法封装
// 添加resolve方法
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    if (value instanceof Promise) {
      value.then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    } else {
      resolve(value)
    }
  })
}
12.Promise.reject方法封装
// 添加reject方法
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
}
13.Promise.all方法封装(难点)

// 返回一个promise,数组中的promise状态全为成功就是成功,
// 值是所有成功的promise组成的数组

// 添加all方法
// 返回一个promise,数组中的promise状态全为成功就是成功,
// 值是所有成功的promise组成的数组
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let count = 0
    let arr = []
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(v => {
        count++
        arr[i] = v
        if (count === promises.length) {
          resolve(arr)
        }
      }, r => {
        this.reject(r)
      })
    }
  })
}
14.Promise.race方法封装
// 添加race方法
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    }
  })
}
15.细节:then方法的回调是异步执行的

它是异步执行的,其它同步代码执行完它才会执行,只需要在resolve、reject函数还有下图两个位置加个定时器,即调用onResolved和onRejected函数的地方

执行结果应该是132

    if (this.promiseState === 'fulfilled') {
      setTimeout(() => {
        callback(onResolved)
      })

    }
    if (this.promiseState === 'rejected') {
      setTimeout(() => {
        callback(onRejected)
      });
16.class版本
class Promise {
  constructor(executor) {
    this.promiseState = 'pending'
    this.promiseResult = null
    this.callbacks = []
    const self = this
    // resolve函数
    //如果写成function,里面的this指向为window,所以写成箭头函数
    // 或者在外面用self保存好this
    function resolve(data) {
      // 判断状态,只有pending的时候才能改变状态
      // 即状态只能改变一次
      if (self.promiseState !== 'pending') return
      // 1.功能:修改对象的状态promiseState
      self.promiseState = 'fulfilled'
      // 2.设置对象结果值(promiseResult)
      self.promiseResult = data
      // 状态改变了再去执行then的回调函数
      setTimeout(() => {
        self.callbacks.forEach((item) => {
          item.onResolved(data)
        })
      })

    }
    // reject函数
    function reject(data) {
      if (self.promiseState !== 'pending') return
      // 1.功能:修改对象的状态promiseState
      self.promiseState = 'rejected'
      // 2.设置对象结果值(promiseResult)
      self.promiseResult = data
      // 状态改变了再去执行then的回调函数
      setTimeout(() => {
        self.callbacks.forEach((item) => {
          item.onRejected(data)
        })
      })

    }


    try {
      // 同步调用函数执行器
      executor(resolve, reject)
    } catch (e) {
      // 修改promise状态为失败
      reject(e)
    }

  }
  then(onResolved, onRejected) {
    const self = this
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    // then的返回值是一个promise
    return new Promise((resolve, reject) => {
      function callback(type) {
        try {
          // 获取回调函数的执行结果
          let result = type(self.promiseResult)
          if (result instanceof Promise) {
            // 如果是Promise对象,修改当前要返回的Promise的状态和值
            result.then(value => {
              resolve(value)
            }, reason => {
              reject(reason)
            })
          } else {
            // 结果对象状态为成功
            resolve(result)
          }
        } catch (e) {
          reject(e)
        }
      }
      // 分别判断,调用这两个函数
      if (this.promiseState === 'fulfilled') {
        setTimeout(() => {
          callback(onResolved)
        })

      }
      if (this.promiseState === 'rejected') {
        setTimeout(() => {
          callback(onRejected)
        });

      }
      if (this.promiseState === 'pending') {
        // 要把回调函数保存到自身上。
        this.callbacks.push({
          onResolved: function () {
            callback(onResolved)
          },
          onRejected: function () {
            callback(onRejected)
          }
        })
      }
    })
  }
  catch(onRejected) {
    return this.then(undefined, onRejected)
  }
  static resolve(value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(value)
      }
    })
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let count = 0
      let arr = []
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(v => {
          count++
          arr[i] = v
          if (count === promises.length) {
            resolve(arr)
          }
        }, r => {
          this.reject(r)
        })
      }
    })
  }
  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      }
    })
  }
}

四、async函数和await表达式(难点)

1.async函数

(1)函数的返回值是promise对象

(2)promise对象的结果由asynac函数执行的返回值决定

2.await表达式

(1)await右侧的表达式一般为promise对象,但也可以是其它值

(2)如果表达式是promise对象,await返回的是promise成功的值

(3)如果表达式是其它值,直接将此值作为await的返回值

注意

1.await必须写在async函数中,但async函数可以没有await

2.如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理

 <script>
    async function main() {
      // 1.右侧为promise的情况
      let p = new Promise((resolve, reject) => {
        reject('shibai')
      })
      try {
        let res = await p
      } catch (e) {
        console.log(e)
      }

      let res2 = await 20
      console.log(res2)
    }
    main()
  </script>

3.async和await结合

可以避免回调地狱的问题

(1)文件读取

const fs = require('fs')
const util = require('util')
const myRead = util.promisify(fs.readFile)
async function main() {
  try {
    let data1 = await myRead('./resource/context.txt')
    console.log(data1.toString())
  } catch (e) {
    console.log(e)
  }
}
main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值