Promise(简介、基本使用、API、手写实现 Promise、async与await)

前言

笔记根据视频与PPT进行整理
【视频链接:尚硅谷Web前端Promise教程从入门到精通】
【视频资源链接–阿里云盘】
【个人代码笔记–阿里云盘】
【视频资源个人代码笔记链接–百度网盘链接】
提取码:1234
字数4.5w+
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第1张图片


目录

Promise

  • 前言
  • 目录
  • 1. Promise 简介
  • 2. Promise 基本使用
    • 2.1 Promise 基本使用体验
      • 回调函数实现:
      • 基于 Promise 实现:
    • 2.2 基于 promise 的形式读取文件
      • 回调函数形式实现:
      • 基于 Promise 实现:
    • 2.3 基于 Promise 的 ajax 请求
    • 2.4 基于 Promise 封装 fs 模块读取文件
    • 2.5 util.promisify 方法封装转化成 Promise
    • 2.6 Promise封装AJAX操作
    • 2.7 promise 的状态
    • 2.8 promise 的基本流程
  • 3. Promise API
    • 3.1 Promise 构造函数
    • 3.2 Promise.prototype.then 方法
    • 3.3 Promise.prototype.catch 方法
    • 3.4 Promise.resolve 方法
    • 3.5 Promise.reject 方法
    • 3.6 Promise.all 方法
    • 3.7 Promise.race 方法
  • 4. promise 的几个关键问题
    • 4.1 如何改变 promise 的状态
    • 4.2 一个 promise 指定多个成功/失败回调函数
    • 4.3 改变 promise 状态和指定回调函数谁先谁后
    • 4.4 promise.then()返回的新 promise 的结果状态
    • 4.5 promise 串连多个操作任务(链式调用)
    • 4.6 promise 异常传透
    • 4.7 中断 promise 链
  • 5. 自定义手写实现 Promise
    • 5.1 定义整体结构
    • 5.2 Promise 构造函数的实现
      • 5.2.1 resolve与reject结构搭建
      • 5.2.2 resolve与reject函数实现
      • 5.2.3 throw抛出错误改变状态
      • 5.2.3 状态只能修改一次
      • 5.2.4 测试
      • 5.2.5 保存实例对象的this
      • 5.2.6 再测试
    • 5.3 promise.then()的实现
      • 5.3.1 then() 实现
      • 5.3.2 then() 异步回调执行实现
      • 5.3.3 then() 指定多个回调函数
      • 5.3.4 同步任务下then()返回结果的实现
        • 执行流程图
      • 5.3.5 异步任务下then()返回结果的实现
      • 5.3.6 then()代码优化
    • 5.4 Promise.catch()实现
      • 5.4.1 catch()实现
      • 5.4.2 异常穿透实现
      • 5.4.3 值传递实现
    • 5.5 resolve() 实现
    • 5.6 reject() 实现
    • 5.7 all() 实现
    • 5.8 race()实现
    • 5.9 then方法回调的异步执行
    • 5.10 封装为Promise类
  • 6 async与await
    • 6.1 mdn 文档
    • 6.2 async 函数
    • 6.3 await 表达式
    • 6.4 async与await结合实践 -- 读取文件
      • 6.4.1 不基于Promise实现 -- 回调地狱
      • 6.4.2 基于Promise


1. Promise 简介

Promise 是一门新的技术(ES6 规范)

Promise 是 JS 中进行异步编程的新解决方案。(旧方案是单纯使用回调函数)

异步编程:

  • fs 文件操作
  • 数据库操作
  • AJAX
  • 定时器

旧方案中单纯使用回调函数,很可能会出现回调地狱(回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件)的问题,不便于阅读,可读性差,不便于异常处理。

回调地狱:
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第2张图片
Promise 支持链式调用, 可以解决回调地狱问题

2. Promise 基本使用

从语法上来说: Promise 是一个构造函数。

从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值。

2.1 Promise 基本使用体验

实现一个小功能:
点击按钮后显示是否中奖(30%概率中奖),若中奖弹出 “恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券” ,若未中奖弹出 “再接再厉”。

回调函数实现:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 初体验h2>
    <button class="btn btn-primary" id="btn">点击抽奖button>
  div>
  
  <script>
    //生成随机数
    function rand(m,n){
      return Math.ceil(Math.random() * (n-m+1)) + m-1;
    }
    /**
    点击按钮后显示是否中奖(30%概率中奖)
      若中奖弹出   恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
      若未中奖弹出 再接再厉
    */
    //获取元素对象
    const btn = document.querySelector('#btn');
    //绑定单击事件
    btn.addEventListener('click', function(){
      // 定时器
      setTimeout(() => {
          //30%  1-100 取出一个数字,小于等于30==中奖
          //获取从1 - 100的一个随机数
          let n = rand(1, 100);
          //判断
          if(n <= 30){
              alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券');
          }else{
              alert('再接再厉');
          }
      }, 0);
    })
  script>
body>
html>

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第3张图片

基于 Promise 实现:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 初体验h2>
    <button class="btn btn-primary" id="btn">点击抽奖button>
  div>
  
  <script>
    //生成随机数
    function rand(m,n){
      return Math.ceil(Math.random() * (n-m+1)) + m-1;
    }
    /**
    点击按钮后显示是否中奖(30%概率中奖)
      若中奖弹出   恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
      若未中奖弹出 再接再厉
    */
    //获取元素对象
    const btn = document.querySelector('#btn');
    //绑定单击事件
    btn.addEventListener('click', function(){
      //Promise 形式实现
      // Promise 构造函数接收的参数为一个函数(函数的参数为两个函数)
      // resolve 解决  函数类型的数据
      // reject  拒绝  函数类型的数据

      // 1) 创建 promise 对象(pending 状态), 指定执行器函数
      const p = new Promise((resolve, reject)=>{
        // 2) 在执行器函数中启动异步任务
        setTimeout(() => {
            let n = rand(1, 100);
            //判断
            // 3) 根据结果做不同处理
            if(n <= 30){
              // 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
              resolve(n); // 将 promise 对象的状态设置为 『成功』调用 resolve 函数
            }else{
              // 如果失败了, 调用 reject(), 指定失败的 reason, 变为 rejected 状态
              reject(n); // 将 promise 对象的状态设置为 『失败』调用 reject 函数
            }
        }, 0);
      })

      //调用 then 方法
      // 指定成功和失败要执行的函数
      // 状态为成功,调用第一个函数,状态为失败,执行第二个函数

	  // 成功失败函数的参数
      // value 值 成功函数参数
      // reason 理由 失败函数参数
      p.then((value) => {
          alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券, 您的中奖数字为 ' + value);
      }, (reason) => {
          alert('再接再厉, 您的号码为 ' + reason);
      });

    })
  script>
body>
html>

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第4张图片

2.2 基于 promise 的形式读取文件

回调函数形式实现:

// 导入 fs 模块
const fs = require('fs');

// 回调函数的方式读取文件
fs.readFile( './content.txt', (err, data)=>{
  if ( err ) throw err // 出错抛出错误
  console.log( data.toString() ) //输出内容
} )

在这里插入图片描述

基于 Promise 实现:

// 导入 fs 模块
const fs = require('fs')

// 基于promise读取文件
const p = new Promise( (resolve, reject)=>{
  fs.readFile( './content.txt', (err, data)=>{
    if ( err ) reject( err )
    else resolve( data )
  } )
} )
// 调用then处理读取文件的结果
p.then( value=>{
  console.log( value.toString() )
}, reason=>{
  console.log(reason)
} )

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第5张图片

2.3 基于 Promise 的 ajax 请求

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise 封装 AJAXtitle>
head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 封装 AJAX 操作h2>
    <button class="btn btn-primary" id="btn">点击发送 AJAXbutton>
  div>
  <script>
    // 接口地址 https://api.liulongbin  跨域了
    // https://www.escook.cn/api/get  跨域了
    // 获取按钮
    const btn = document.querySelector('#btn')

    btn.addEventListener( 'click', ()=>{
      // 创建 Promise 对象
      const p = new Promise( (resolve, reject)=>{
        // 创建请求对象
        const xhr = new XMLHttpRequest()
        
        // 初始化
        xhr.open( 'GET', 'https://www.escook.cn/api/get' ) // 跨域了
        // 设置请求头
        // xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        // 发送请求
        xhr.send()
        // 处理响应的结果
        xhr.onreadystatechange = ()=>{
          if ( xhr.readyState===4 ) {
            // 成功
            if ( xhr.status>=200 && xhr.status<300 ) {
              // 请求响应信息 xhr.response
              resolve( xhr.response )
            } else {
              // xhr.status 请求状态
              reject( xhr.status )
            }
          }
        }
      } )
      p.then( value=>{
        console.log( value )
      }, reason=>{
        console.log( reason )
      } )
    } )
  script>
body>

请求失败,调用失败的处理函数,打印请求状态码
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第6张图片

2.4 基于 Promise 封装 fs 模块读取文件

/**
 * 封装一个函数 mineReadFile 读取文件内容
 * 参数:  path  文件路径
 * 返回:  promise 对象
 */
// 导入 fs
const fs = require( 'fs' )

const mineReadFile = ( path )=>{
  return new Promise( (resolve, reject)=>{
    fs.readFile( path, ( err, data )=>{
      if(err) reject(err)
      resolve(data)
    } )
  } )
}

// 调用读取文件的方法
// 指定对应的成功和失败的处理函数
mineReadFile( './content.txt' )
.then( val=>{
  // 输出文件的内容
  console.log( val.toString() )
}, reason=>{
  // 输出错误信息
  console.log( reason )
} )

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第7张图片

2.5 util.promisify 方法封装转化成 Promise

/**
 * util.promisify 方法
 */
// 引入 util 模块
const util = require( 'util' )
// 引入 fs 模块
const fs = require( 'fs' )
// 使用 util.promisify 方法封装 fs.readFile 
// 参数为一个函数
const mineReadFile = util.promisify( fs.readFile )
// 调用函数,并且指定对应的成功和失败处理函数
mineReadFile( './content.txt' ).then( val=>{
  console.log( val.toString() )
}, reason=>{
  console.log( reason )
} )

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第8张图片

2.6 Promise封装AJAX操作

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>
<body>
  <script>
    /**
     * 封装一个函数 sendAJAX 发送 GET AJAX 请求
     * 参数   URL
     * 返回结果 Promise 对象
     */
    function sendAJAX( url ) {
      return new Promise( (resolve, reject)=>{
        const xhr = new XMLHttpRequest()
        xhr.responseType = 'json'
        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('https://api.apiopen.top/getJok')
    .then(value => {
      console.log(value);
    }, reason => {
      console.warn(reason);
    });
  script>
body>
html>

依旧跨域问题,请求失败,调用失败的处理函数,打印请求状态码
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第9张图片

2.7 promise 的状态

在这里插入图片描述

实例对象中的一个属性 『PromiseState』

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

promise 的状态改变

  1. 成功 pending 变为 resolved / fullfilled
  2. 失败 pending 变为 rejected

说明:
只有这 2 种(只能pending 变为 resolved / fullfilled 或 pending 变为 rejected,没有其他的状态变化), 且一个 promise 对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason。

2.8 promise 的基本流程

promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个) => 根据函数中执行成功或失败的结果,改变promise的状态 => 调用对应的成功或失败的函数。

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第10张图片

3. Promise API

3.1 Promise 构造函数

Promise (excutor)
  • (1) executor 函数: 执行器 (resolve, reject) => {}
  • (2) resolve 函数: 内部定义成功时我们调用的函数 value => {}
  • (3) reject 函数: 内部定义失败时我们调用的函数 reason => {}

executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行,执行构造函数时会立即执行 executor 函数。

    // 成功
    // 创建Promise实例对象时同步执行传入的执行器函数
    const p1 = new Promise( (resolve, reject)=>{
      console.log( 'executor 执行' )
      if(true) {
        resolve()
      } else {
        reject()
      }
    } )
    console.log( p1 )
    // 失败
    const p2 = new Promise( (resolve, reject)=>{
      console.log( 'executor 执行' )
      if(false) {
        resolve()
      } else {
        reject()
      }
    } )
    console.log( p2 )

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第11张图片

3.2 Promise.prototype.then 方法

Promise.prototype.then 方法: (onResolved, onRejected) => {}
  • (1) onResolved 函数: 成功的回调函数 (value) => {}
  • (2) onRejected 函数: 失败的回调函数 (reason) => {}

指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调返回一个新的 promise 对象

    // 成功
    const p1 = new Promise( (resolve, reject)=>{
      resolve('ok')
    } )
    // 执行第一个函数 -- 成功的回调函数
    p1.then( val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    } )
    // 失败
    const p2 = new Promise( (resolve, reject)=>{
      reject('Error')
    } )
    // 执行第二个函数 -- 失败的回调函数
    p2.then( val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    } )

在这里插入图片描述

3.3 Promise.prototype.catch 方法

Promise.prototype.catch 方法: (onRejected) => {}
  • onRejected 函数: 失败的回调函数 (reason) => {}

then()的语法糖, 相当于: then(undefined, onRejected)

catch 定义用于处理失败的回调函数,不定义成功的回调函数

    const p = new Promise( (resolve, reject)=>{
      reject('error')
    } )
    // Promise的状态为失败时才调用catch中的回调函数
    p.catch( reason=>{
      console.log(reason)
    } )

    const pp = new Promise( (resolve, reject)=>{
      resolve('ok')
    } )
    // Promise的状态为失败时才调用catch中的回调函数
    pp.catch( reason=>{
      console.log(reason)
    } )

在这里插入图片描述

3.4 Promise.resolve 方法

Promise.resolve 方法: (value) => {}
  • value: 成功的数据或 promise 对象

返回一个成功/失败的 promise 对象

    // 如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
    const p1 = Promise.resolve( 123 )
    console.log(p1)
    // 如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
    const p2 = Promise.resolve( new Promise( (resolve, reject)=>{
      resolve('ok')
    } ) ) 
    console.log(p2);
    const p3 = Promise.resolve( new Promise( (resolve, reject)=>{
      reject('error')
    } ) ) 
    console.log(p3);

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第12张图片

3.5 Promise.reject 方法

Promise.reject 方法: (reason) => {}
  • reason: 失败的原因

返回一个失败的 promise 对象

    const p1 = Promise.reject( new Promise((resolve, reject)=>{
      resolve('ok')
    }) )
    console.log(p1)

在这里插入图片描述

3.6 Promise.all 方法

Promise.all 方法: (promises) => {}
  • promises: 包含 n 个 promise 的数组

返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败

    const p1 = Promise.resolve('OK')
    const p2 = Promise.reject('Error')
    // 处理失败,防止报错
    p2.catch( reason=>{} )
    const p3 = new Promise( (resolve, reject)=>{
      resolve('ok')
    } )
    // p1 p3 的状态为成功,p2 为失败,res1的状态为失败
    const res1 = Promise.all( [p1, p2, p3] )
    // 处理失败,防止报错
    res1.catch( reason=>{} )
    // p1 p3 的状态为成功,res2的状态为成功
    const res2 = Promise.all( [p1, p3] )
    console.log( res1 )
    console.log( res2 )

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第13张图片

3.7 Promise.race 方法

Promise.race 方法: (promises) => {}
  • promises: 包含 n 个 promise 的数组

返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态

      const p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('ok')
        }, 1000)
      })
      const p2 = Promise.resolve('ok')
      const p3 = Promise.reject('err')
      const res = Promise.race([p1, p2, p3])
      console.log(res)

第一个完成的Promise为 p2
p2状态为成功,最后结果为成功
在这里插入图片描述

4. promise 的几个关键问题

4.1 如何改变 promise 的状态

  • (1) resolve(value): 如果当前是 pending 就会变为 resolved
  • (2) reject(reason): 如果当前是 pending 就会变为 rejected
  • (3) 抛出异常: 如果当前是 pending 就会变为 rejected
    let p = new Promise( (resolve, reject)=>{
      resolve('ok')
    } )
    // resolve -- 成功
    console.log(p)

    p = new Promise( (resolve, reject)=>{
      reject('ok')
    } )
    // reject -- 失败
    console.log(p)

    p = new Promise( (resolve, reject)=>{
      throw 'err'
    } )
    // 抛出错误为失败
    console.log(p)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第14张图片

4.2 一个 promise 指定多个成功/失败回调函数

一个 promise 指定多个成功/失败回调函数, 都会调用吗?

  • 当 promise 改变为对应状态时都会调用
      let p = new Promise((resolve, reject) => {
        resolve('OK');
      })
	  // 状态为成功,后面的成功的回调函数都会被调用
      p.then( val=>{
        console.log('成功的回调函数')
      } )
      p.then( val=>{
        console.log('成功的回调函数')
      } )
      p.then( val=>{
        console.log('成功的回调函数')
      } )

在这里插入图片描述

4.3 改变 promise 状态和指定回调函数谁先谁后

  • (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  • (2) 如何先改状态再指定回调?
    • ① 在执行器中直接调用 resolve()/reject()
    • ② 延迟更长时间才调用 then()
    • 看回调函数在执行器中调用的时间
  • (3) 什么时候才能得到数据?
    • ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    • ② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
    • 回调函数调用, 得到数据
      // 先指定回调函数
      // 再改变状态
      // 执行器中的执行的为异步任务,调用回调函数在1秒后
      let p = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('OK')
        }, 1000)
      })
      p.then(
        (value) => {
          console.log(value)
        },
        (reason) => {}
      )
      // 先改变状态
      // 执行器内为同步任务
      // 执行执行器就立马调用成功的回调函数
      // 先改变状态在指定回调函数
      p = new Promise((resolve, reject) => {
        resolve('OK')
      })
      p.then(
        (value) => {
          console.log(value)
        },
        (reason) => {}
      )

4.4 promise.then()返回的新 promise 的结果状态

promise.then()返回的新 promise 的结果状态由什么决定?

  • (1) 简单表达: 由 then()指定的回调函数执行的结果决定
  • (2) 详细表达:
    • ① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
    • ② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
    • ③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
      // 1
      let p = new Promise((resolve, reject) => {
        resolve('ok')
      })
      let res = p.then(
        (val) => {
          throw 'err'
        },
        (reason) => {}
      )
      console.log(res)
      // 2
      p = new Promise((resolve, reject) => {
        resolve('ok')
      })
      res = p.then(
        (val) => {
          return 123
        },
        (reason) => {}
      )
      console.log(res)
      // 3
      p = new Promise((resolve, reject) => {
        resolve('ok')
      })
      res = p.then(
        (val) => {
          return new Promise.reject('Err')
        },
        (reason) => {}
      )
      console.log(res)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第15张图片

4.5 promise 串连多个操作任务(链式调用)

  • (1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
  • (2) 通过 then 的链式调用串连多个同步/异步任务
      let p = new Promise((resolve, reject) => {
        resolve('ok')
      })
      p.then((val) => {
        return new Promise((resolve, reject) => {
          resolve('OK')
        })
      })
        .then((val) => {
          console.log(val)
        })
        .then((val) => {
          // 上一个then结果集中没有返回值,结果集为undefined
          // 输出为undefined
          console.log(val)
        })

在这里插入图片描述

4.6 promise 异常传透

  • (1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
  • (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理
      let p = new Promise((resolve, reject) => {
        resolve('ok')
      })
      p.then( val=>{
        throw 'err'
      } ).then( val=>{
        console.log(222);
      } ).then( val=>{
        console.log(222);
      } ).catch( reason=>{
        console.log(reason)
      } )

出错之后直接到catch,中的其他then不执行
在这里插入图片描述

4.7 中断 promise 链

  • (1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
  • (2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象 (有且只有一个方式)
let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('OK');
            }, 1000);
        });

        p.then(value => {
            console.log(111);
            //有且只有一个方式
            // 新创建的Promise对象,且没有调用回调函数,或抛出错误
            // 对象的状态没有改变
            // 所以该Promise对象的状态为pending
            // 下面的then,catch定义的为失败或成功的回调函数
            // 所以会中断退出,不会继续向下执行
            return new Promise(() => {});
        }).then(value => {
            console.log(222);
        }).then(value => {
            console.log(333);
        }).catch(reason => {
            console.warn(reason);
        });

5. 自定义手写实现 Promise

5.1 定义整体结构

// 定义Promise的构造函数
function Promise(excutor) {

}

// 定义Promise的then函数
// 定义在prototype上
Promise.prototype.then = function () {
  
}

官方的 Promise 的实例化对象的 then 等函数都在其原型链上,所以自定义的 Promise 的 then 等函数也挂在原型链上。
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第16张图片

5.2 Promise 构造函数的实现

// 定义Promise的构造函数
function Promise(excutor) {
  // 在执行构造函数时会同步立即执行执行器函数
  // 调用传参传过来的执行器函数
  // 执行器函数中有两个参数,resolve函数与reject函数
  // 执行执行器函数需要传入两个参数,resolve函数与reject函数
  excutor(resolve, reject)
}

5.2.1 resolve与reject结构搭建

// 定义Promise的构造函数
function Promise(excutor) {
  // 执行器函数执行过程中会调用resolve或reject函数改变Promise的状态
  // resolve与reject函数需要定义
  // 定义resolve函数
  // 会传递过来一个参数,用于改变Promise的结果值 PromiseResult
  function resolve(data) {

  }

  // 定义reject函数
  // 会传递过来一个参数,用于改变Promise的结果值 PromiseResult
  function reject(data) {
    
  }

  // 调用传参传过来的执行器函数
  excutor(resolve, reject)
}

5.2.2 resolve与reject函数实现

// 定义Promise的构造函数
function Promise(excutor) {
  // resolve函数与reject函数改变 Promise的状态 PromiseState 和 Promise的结果 PromiseResult
  // PromiseState PromiseResult 每个 Promise 对象都有,所以定义在构造函数中
  this.PromiseState = 'pending' // 默认状态 pending
  this.PromiseResult = null // 结果默认为空

  // 定义resolve函数
  function resolve(data) {
    // 修改 Promise的状态 PromiseState 为成功 fulfilled/resolved
    this.PromiseState = 'fulfilled'
    // 修改 Promise的结果 PromiseResult 为 data
    this.PromiseResult = data
  }

  // 定义reject函数
  function reject(data) {
    // 修改 Promise的状态 PromiseState 为成功 rejected
    this.PromiseState = 'rejected'
    // 修改 Promise的结果 PromiseResult 为 data
    this.PromiseResult = data
  }

  // 调用传参传过来的执行器函数  同步调用
  excutor(resolve, reject)
}

5.2.3 throw抛出错误改变状态

// 定义Promise的构造函数
function Promise(excutor) {
  // 定义 PromiseState PromiseResult 
  this.PromiseState = 'pending' // 默认状态 pending
  this.PromiseResult = null // 结果默认为空

  // 定义resolve函数
  function resolve(data) {
    this.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    this.PromiseResult = data       // 修改 Promise的结果 PromiseResult
  }

  // 定义reject函数
  function reject(data) {
    this.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    this.PromiseResult = data       // 修改 Promise的结果 PromiseResult
  }

  // 异常在 excutor 中抛出的
  // 捕获 excutor 中的异常并进行处理
  try {
    // 调用传参传过来的执行器函数  同步调用
    excutor(resolve, reject)
  } catch(e) {
    // 处理异常
    // 改变Promise状态为失败,改变结果
    // 直接调用 reject 函数 传入失败信息
    reject(e)
  }
  
}

5.2.3 状态只能修改一次

Promise 的状态只能修改一次,只能从 pending 到成功或从 pending 到失败,没有其他可能的改变

// 定义Promise的构造函数
function Promise(excutor) {
  // 定义 PromiseState PromiseResult 
  this.PromiseState = 'pending' // 默认状态 pending
  this.PromiseResult = null // 结果默认为空

  // 定义resolve函数
  function resolve(data) {
    // 状态只能修改一次
    // 如果状态已经修改了(即不为pending)就直接退出
    if (this.PromiseState !== 'pending') return;
    this.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    this.PromiseResult = data       // 修改 Promise的结果 PromiseResult
  }

  // 定义reject函数
  function reject(data) {
    // 状态只能修改一次
    // 如果状态已经修改了(即不为pending)就直接退出
    if (this.PromiseState !== 'pending') return;
    this.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    this.PromiseResult = data       // 修改 Promise的结果 PromiseResult
  }

  // 捕获 excutor 中的异常并进行处理
  try {
    // 调用传参传过来的执行器函数  同步调用
    excutor(resolve, reject)
  } catch (e) {
    // 处理异常,改变Promise状态为失败,改变结果
    reject(e)
  }

}

5.2.4 测试

    // 成功状态测试
    let p1 = new Promise( (resolve, reject)=>{
      resolve('OK')
    } )
    // p.then(val=>{
    //   console.log(val)
    // }, reason=>{
    //   console.log(reason)
    // })
    console.log(p1)
    // 失败状态测试
    let p2 = new Promise( (resolve, reject)=>{
      reject('error')
    } )
    console.log(p2)
    // 抛出异常测试
    let p3 = new Promise( (resolve, reject)=>{
      throw 'Error'
    } )
    console.log(p3)

会发现Promise的状态和结果没有进行更改

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第17张图片

造成的原因:创建Promise对象时,传入的执行器函数为箭头函数,箭头函数没有自己的this,箭头函数的this会指向外层的this。

<body>
  <script>
	let p1 = new Promise( (resolve, reject)=>{
      resolve('OK')
    } )
  script>
body>

箭头函数的外层为页面,外层的this指向window,所以箭头函数的this指向window,因此需要想办法让传入执行器为箭头函数this指向Promise对象

5.2.5 保存实例对象的this

// 定义Promise的构造函数
function Promise(excutor) {
  // 定义 PromiseState PromiseResult 
  this.PromiseState = 'pending' // 默认状态 pending
  this.PromiseResult = null // 结果默认为空

  // 在构造 Promise 对象时将 Promise 对象的 this 保存下来
  // 修改时修改 self 上的属性即可,self 指向本对象的this
  // self 就是本对象
  const self = this

  // 定义resolve函数
  function resolve(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
  }

  // 定义reject函数
  function reject(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
  }

  // 捕获 excutor 中的异常并进行处理
  try {
    // 调用传参传过来的执行器函数  同步调用
    excutor(resolve, reject)
  } catch (e) {
    // 处理异常,改变Promise状态为失败,改变结果
    reject(e)
  }

}

5.2.6 再测试

<body>
  <script>
    // 成功状态测试
    let p1 = new Promise( (resolve, reject)=>{
      resolve('OK')
    } )
    // p.then(val=>{
    //   console.log(val)
    // }, reason=>{
    //   console.log(reason)
    // })
    console.log(p1)
    // 失败状态测试
    let p2 = new Promise( (resolve, reject)=>{
      reject('error')
    } )
    console.log(p2)
    // 抛出异常测试
    let p3 = new Promise( (resolve, reject)=>{
      throw 'Error'
    } )
    console.log(p3)
  script>
body>

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第18张图片

后面补的执行图Promise(简介、基本使用、API、手写实现 Promise、async与await)_第19张图片

5.3 promise.then()的实现

5.3.1 then() 实现

// 定义 Promise 的 then 方法
// 定义在 prototype 上
// then 方法中有两个函数类型的参数 成功状态的回调函数和失败状态的回调函数
Promise.prototype.then = function (onResolved, onRejected) {
  // 根据 Promise 的状态 PromiseState 判断要调用哪个回调函数
  // 状态为成功
  if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
    onResolved( this.PromiseResult )
  }
  // 状态为失败
  if (this.PromiseState === 'rejected') {
    onRejected( this.PromiseResult )
  }
}

then 方法不为箭头函数,为普通函数,有自己的this,指向调用该方法的实例对象

测试:

<body>
  <script>
    // 成功状态测试
    console.log('===== 成功状态测试 =====')
    let p1 = new Promise( (resolve, reject)=>{
      resolve('OK')
    } )
    p1.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(p1)
    // 失败状态测试
    console.log('===== 失败状态测试 =====')
    let p2 = new Promise( (resolve, reject)=>{
      reject('error')
    } )
    p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(p2)
    // 抛出异常测试
    console.log('===== 抛出异常测试 =====')
    let p3 = new Promise( (resolve, reject)=>{
      throw 'Error'
    } )
    p3.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(p3)
  script>
body>

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第20张图片

5.3.2 then() 异步回调执行实现

执行器函数中改为异步任务,会发现没有任何输出

    let p1 = new Promise( (resolve, reject)=>{
      setTimeout(()=>{
        resolve('OK')
      }, 500)
    } )
    p1.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第21张图片

原因:

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第22张图片
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第23张图片

所以 then() 中的回调函数并未执行,不会有任何的输出。then() 中缺少对于pending状态时候的判断,需要增加对于pending状态的判断。

// 定义 Promise 的 then 方法
// 定义在 prototype 上
// then 方法中有两个函数类型的参数 成功状态的回调函数和失败状态的回调函数
Promise.prototype.then = function (onResolved, onRejected) {
  // 根据 Promise 的状态 PromiseState 判断要调用哪个回调函数
  // 状态为成功
  if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
    onResolved(this.PromiseResult)
    console.log(this)
  }
  // 状态为失败
  if (this.PromiseState === 'rejected') {
    onRejected(this.PromiseResult)
    console.log(this)
  }
  // 状态为 pending
  if (this.PromiseState === 'pending') {
    // then() 中回调函数执行的时机为 Promise 状态改变之后
    // 所以回调函数应该在状态改变之后进行调用
    // 因此回调函数在resolve或reject函数中转台改变之后进行调用
    // 但是resolve和reject与then为不同的函数,不同的函数作用域
    // 需要将回调函数进行保存后才可以在resolve或reject中进行调用
    // 在构造函数中声明一个对象来保存回调函数
    // 在then()使用其来保存回调函数
    this.callback = {
      onResolved: onResolved,
      onRejected: onRejected
    }
    // 简写
    // this.callback = {
    //   onResolved,
    //   onRejected
    // }
  }
}
  // 在构造函数中声明一个回调函数对象用于保存回调函数,
  // 以便在resolve或reject中执行
  this.callback = {}
// 定义Promise的构造函数
function Promise(excutor) {
  // 定义 PromiseState PromiseResult 
  this.PromiseState = 'pending' // 默认状态 pending
  this.PromiseResult = null // 结果默认为空
  const self = this // 将 Promise 对象的 this 保存下来
  // 在构造函数中声明一个回调函数对象用于保存回调函数,
  // 以便在resolve或reject中执行
  this.callback = {}

  // 定义resolve函数
  function resolve(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    // 状态改变之后有成功的回调函数,调用成功的回调函数
    if (self.callback.onResolved) {
      self.callback.onResolved(self.PromiseResult);
    }
  }

  // 定义reject函数
  function reject(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    // 状态改变之后有失败的回调函数,调用失败的回调函数
    if (self.callback.onResolved) {
      self.callback.onResolved(self.PromiseResult);
    }
  }

  // 捕获 excutor 中的异常并进行处理
  try {
    // 调用传参传过来的执行器函数  同步调用
    excutor(resolve, reject)
  } catch (e) {
    // 处理异常,改变Promise状态为失败,改变结果
    reject(e)
  }

}

测试:

    let p1 = new Promise( (resolve, reject)=>{
      setTimeout(()=>{
        resolve('OK')
      }, 500)
    } )
    p1.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    let p2 = new Promise( (resolve, reject)=>{
      setTimeout(()=>{
        reject('err')
      }, 500)
    } )
    p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })

在这里插入图片描述

5.3.3 then() 指定多个回调函数

给p1多指定一个回调函数,会发现只有最后指定的回调函数被执行(原因:后面指定的回调函数覆盖了前面的回调函数)

    let p1 = new Promise( (resolve, reject)=>{
      setTimeout(()=>{
        resolve('OK')
      }, 500)
    } )
    p1.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    p1.then(val=>{
      console.log(val+'!!!!!!!')
    }, reason=>{
      console.log(reason+'!!!!!!!')
    })

在这里插入图片描述

要执行多个回调函数,那么就需要将每个回调函数进行保存,因此改用数组保存回调函数。

  this.callback = [] // 声明一个数组用于保存回调函数
  // 状态为 pending
  if (this.PromiseState === 'pending') {
    this.callback.push({
      onResolved: onResolved,
      onRejected: onRejected
    })
  }
  // 定义resolve函数
  function resolve(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    self.callback.forEach(item=>{ // 调用所有的回调函数
      item.onResolved(self.PromiseResult)
    });
  }

  // 定义reject函数
  function reject(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    self.callback.forEach(item=>{ // 调用所有的回调函数
      item.onRejected(self.PromiseResult)
    });
  }

完整代码:

// 定义Promise的构造函数
function Promise(excutor) {
  // 定义 PromiseState PromiseResult 
  this.PromiseState = 'pending' // 默认状态 pending
  this.PromiseResult = null // 结果默认为空
  const self = this // 将 Promise 对象的 this 保存下来
  this.callback = [] // 声明一个数组用于保存回调函数

  // 定义resolve函数
  function resolve(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    self.callback.forEach(item=>{ // 调用所有的回调函数
      item.onResolved(self.PromiseResult)
    });
  }

  // 定义reject函数
  function reject(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    self.callback.forEach(item=>{ // 调用所有的回调函数
      item.onRejected(self.PromiseResult)
    });
  }

  // 捕获 excutor 中的异常并进行处理
  try {
    // 调用传参传过来的执行器函数  同步调用
    excutor(resolve, reject)
  } catch (e) {
    // 处理异常,改变Promise状态为失败,改变结果
    reject(e)
  }

}

// 定义 Promise 的 then 方法
// 定义在 prototype 上
// then 方法中有两个函数类型的参数 成功状态的回调函数和失败状态的回调函数
Promise.prototype.then = function (onResolved, onRejected) {
  // 根据 Promise 的状态 PromiseState 判断要调用哪个回调函数
  // 状态为成功
  if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
    onResolved(this.PromiseResult)
    console.log(this)
  }
  // 状态为失败
  if (this.PromiseState === 'rejected') {
    onRejected(this.PromiseResult)
    console.log(this)
  }
  // 状态为 pending
  if (this.PromiseState === 'pending') {
    this.callback.push({
      onResolved: onResolved,
      onRejected: onRejected
    })
  }
}

测试:

    let p1 = new Promise( (resolve, reject)=>{
      setTimeout(()=>{
        resolve('OK')
      }, 500)
    } )
    p1.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    p1.then(val=>{
      console.log(val+'!!!!!!!')
    }, reason=>{
      console.log(reason+'!!!!!!!')
    })
    let p2 = new Promise( (resolve, reject)=>{
      setTimeout(()=>{
        reject('err')
      }, 500)
    } )
    p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })

在这里插入图片描述

5.3.4 同步任务下then()返回结果的实现

官方的then()执行完回调函数后会返回一个Promise对象,但是目前自己实现的Promise在执行完回调函数后不会返回一个Promise对象

    let p2 = new Promise( (resolve, reject)=>{
      reject('err')
    } )
    const res2 =  p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(res2)

回调函数执行后没有Promise对象返回
在这里插入图片描述

then()返回Promise对象的状态,执行成功的回调函数为成功,执行失败的回调函数为失败,return一个Promise对象根据return的Promise对象状态进行判断。

以回调函数为失败的回调函数为例:

    // 状态为失败
    if (this.PromiseState === 'rejected') {
      // 获取回调函数执行的结果
      const result = onRejected(this.PromiseResult)
      if (result instanceof Promise) { // 如果是Promise的实例对象
        // 返回的为Promise实例对象,指定了then,那么result状态改变肯定会执行then中回调函数
        result.then(v => {
          resolve(v) // 调用成功函数,改变返回的Promise对象为成功
        }, r => {
          reject(r) // 调用失败函数,改变返回的Promise对象为失败
        })
      } else {
        // 执行的为失败的对调函数,返回的Promise一定为失败
        // 调用返回Promise对象的reject函数改变返回Promise对象的状态和结果
        resolve(result)
      }
    }

测试:

    let p2 = new Promise( (resolve, reject)=>{
      reject('err')
    } )
    const res2 =  p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(res2)

回调函数返回的为空,返回的Promise对象的状态应该为成功,结果为undefined
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第24张图片

回调函数的成功的写法一样:

// 定义 Promise 的 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
  // 执行完then()返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 状态为成功
    if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
      const result = onResolved(this.PromiseResult)
      if (result instanceof Promise) { // 如果是Promise的实例对象
        // 返回的为Promise实例对象,指定了then,那么result状态改变肯定会执行then中回调函数
        result.then(v => {
          resolve(v) // 调用成功函数,改变返回的Promise对象为成功
        }, r => {
          reject(r) // 调用失败函数,改变返回的Promise对象为失败
        })
      } else {
        // 执行的为失败的对调函数,返回的Promise一定为失败
        // 调用返回Promise对象的reject函数改变返回Promise对象的状态和结果
        resolve(result)
      }
    }
    // 状态为失败
    if (this.PromiseState === 'rejected') {
      // 获取回调函数执行的结果
      const result = onRejected(this.PromiseResult)
      if (result instanceof Promise) { // 如果是Promise的实例对象
        // 返回的为Promise实例对象,指定了then,那么result状态改变肯定会执行then中回调函数
        result.then(v => {
          resolve(v) // 调用成功函数,改变返回的Promise对象为成功
        }, r => {
          reject(r) // 调用失败函数,改变返回的Promise对象为失败
        })
      } else {
        // 执行的为失败的对调函数,返回的Promise一定为失败
        // 调用返回Promise对象的reject函数改变返回Promise对象的状态和结果
        reject(result)
      }
    }
    // 状态为 pending
    if (this.PromiseState === 'pending') {
      this.callback.push({
        onResolved: onResolved,
        onRejected: onRejected
      })
    }
  })
}

测试:

    let p1 = new Promise( (resolve, reject)=>{
        resolve('OK')
    } )
    const res1 = p1.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(res1)

    let p2 = new Promise( (resolve, reject)=>{
      reject('err')
    } )
    const res2 =  p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    })
    console.log(res2)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第25张图片

抛出错误处理:

    // 状态为失败
    if (this.PromiseState === 'rejected') {
      try {
        // 获取回调函数执行的结果
        const result = onRejected(this.PromiseResult)
        if (result instanceof Promise) { // 如果是Promise的实例对象
          // 返回的为Promise实例对象,指定了then,那么result状态改变肯定会执行then中回调函数
          result.then(v => {
            resolve(v) // 调用成功函数,改变返回的Promise对象为成功
          }, r => {
            reject(r) // 调用失败函数,改变返回的Promise对象为失败
          })
        } else {
          // 执行的为失败的对调函数,返回的Promise一定为失败
          // 调用返回Promise对象的reject函数改变返回Promise对象的状态和结果
          reject(result)
        }
      } catch (e) {
        // 抛出错误状态就为失败
        reject(e)
      }
    }

测试:

    let p1 = new Promise( (resolve, reject)=>{
        resolve('OK')
    } )
    const res1 = p1.then(val=>{
      console.log(val)
      throw 'error'
    }, reason=>{
      console.log(reason)
    })
    console.log(res1)

    let p2 = new Promise( (resolve, reject)=>{
      reject('err')
    } )
    const res2 =  p2.then(val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
      throw 'error'
    })
    console.log(res2)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第26张图片

执行流程图

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第27张图片

5.3.5 异步任务下then()返回结果的实现

异步任务下then()不会返回有状态的Promise的对象

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('OK')
        }, 1000)
      })
      const res1 = p1.then(
        (val) => {
          console.log(val)
        },
        (reason) => {
          console.log(reason)
        }
      )
      console.log(res1)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第28张图片
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第29张图片

因为回调函数最终执行是在调用then方法对象中的resolve或reject函数中执行
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第30张图片
所以对保存的回调函数进行修改,让其调用将要返回的Promise对象的resolve函数或reject函数。
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第31张图片
需要对调用then的Promise对象进行保存

// 定义 Promise 的 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this // 保存调用then的Promise对象
  ......
}

在保存的函数中调用成功或失败的回调函数,并且执行返回的Promise对象的状态和结果的修改

    // 状态为 pending
    if (this.PromiseState === 'pending') {
      this.callback.push({
        onResolved: function () {
          // 执行成功的回调函数
          // 根据回调函数的结果进行判断,来修改返回对象的状态
          const result = onResolved(self.PromiseResult)
          // 判断
          if (result instanceof Promise) { // 如果是Promise的实例对象
            result.then(v => {
              resolve(v) // 调用成功函数,改变返回的Promise对象为成功
            }, r => {
              reject(r) // 调用失败函数,改变返回的Promise对象为失败
            })
          } else {
            resolve(result)
          }
        },
        onRejected: function () {
          // 执行失败的回调函数
          const result = onResolved(self.PromiseResult)
          // 判断
          if (result instanceof Promise) { // 如果是Promise的实例对象
            result.then(v => {
              resolve(v) // 调用成功函数,改变返回的Promise对象为成功
            }, r => {
              reject(r) // 调用失败函数,改变返回的Promise对象为失败
            })
          } else {
            resolve(result)
          }
        }
      })
    }

测试:

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('OK')
        }, 1000)
      })
      const res1 = p1.then(
        (val) => {
          console.log(val)
        },
        (reason) => {
          console.log(reason)
        }
      )
      console.log(res1)

      let p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
          reject('OK')
        }, 1000)
      })
      const res2 = p2.then(
        (val) => {
          console.log(val)
        },
        (reason) => {
          console.log(reason)
        }
      )
      console.log(res2)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第32张图片
在这里插入图片描述

抛出错误返回的Promise对象

    // 状态为 pending
    if (this.PromiseState === 'pending') {
      this.callback.push({
        onResolved: function () {
          try {
            // 执行成功的回调函数
            // 根据回调函数的结果进行判断,来修改返回对象的状态
            const result = onResolved(self.PromiseResult)
            // 判断
            if (result instanceof Promise) { // 如果是Promise的实例对象
              result.then(v => {
                resolve(v) // 调用成功函数,改变返回的Promise对象为成功
              }, r => {
                reject(r) // 调用失败函数,改变返回的Promise对象为失败
              })
            } else {
              resolve(result)
            }
          } catch (e) {
            reject(e)
          }
        },
        onRejected: function () {
          try {
            // 执行失败的回调函数
            const result = onResolved(self.PromiseResult)
            // 判断
            if (result instanceof Promise) { // 如果是Promise的实例对象
              result.then(v => {
                resolve(v) // 调用成功函数,改变返回的Promise对象为成功
              }, r => {
                reject(r) // 调用失败函数,改变返回的Promise对象为失败
              })
            } else {
              resolve(result)
            }
          } catch (e) {
            reject(e)
          }
        }

测试:

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('OK')
        }, 1000)
      })
      const res1 = p1.then(
        (val) => {
          console.log(val)
          throw 'ERROR'
        },
        (reason) => {
          console.log(reason)
        }
      )
      console.log(res1)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第33张图片

5.3.6 then()代码优化

会发现三个if中的代码类似,就回调函数有所不同,可以写到外面封装为函数,利于后期维护
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第34张图片
注意this的指向

// 定义 Promise 的 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this // 保存调用then的Promise对象
  // 执行完then()返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 封装函数
    function callback(type) {
      try {
        // 使用this,this指向的不为调用then的Promise对象
        const result = type(self.PromiseResult)
        if (result instanceof Promise) { // 如果是Promise的实例对象
          result.then(v => {
            resolve(v) // 调用成功函数,改变返回的Promise对象为成功
          }, r => {
            reject(r) // 调用失败函数,改变返回的Promise对象为失败
          })
        } else {
          resolve(result)
        }
      } catch (e) {
        reject(e)
      }
    }
    // 状态为成功
    if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
      callback(onResolved)
    }
    // 状态为失败
    if (this.PromiseState === 'rejected') {
      callback(onRejected)
    }
    // 状态为 pending
    if (this.PromiseState === 'pending') {
      this.callback.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

5.4 Promise.catch()实现

5.4.1 catch()实现

// 定义 Promise 的 catch 方法
Promise.prototype.catch = function (onRejected) {
  // catch 方法中执行的是失败的回调函数
  // 与 then 差别为只有失败的回调函数,可以直接使用then
  return this.then( undefined, onRejected )
}
      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          reject('Error')
        }, 1000)
      })
      const res1 = p1.catch(reason=>{
        console.log(reason)
      })
      console.log(res1)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第35张图片

5.4.2 异常穿透实现

在then的链式调用的过程中不需要对失败的结果进行处理,主要在最后加一个catch方法处理失败的结果即可。

未实现异常穿透测试:

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          reject('Error')
        }, 1000)
      })

      p1.then((v) => {
        console.log(111)
      })
        .then((v) => {
          console.log(222)
        })
        .catch((r) => {
          console.log(r)
        })

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第36张图片

原因:
Promise(简介、基本使用、API、手写实现 Promise、async与await)_第37张图片
实现异常穿透:

// 定义 Promise 的 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this // 保存调用then的Promise对象
  
  // 判断失败的回调函数
  // 由于报错造成的原因是失败的回调函数为undefined
  // 所以当失败的回调函数为未定义时候,补充一个失败回调
  // 让其报错
  if (typeof onRejected !== 'function' ) {
    onRejected = reason => {
      throw reason
    }
  }
  
  ......
}

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第38张图片
测试:

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          // reject('Error')
          resolve('OK')
        }, 1000)
      })

      p1.then((v) => {
        console.log(111)
        throw 'ERROR'
      })
        .then((v) => {
          console.log(222)
          
        })
        .catch((r) => {
          console.log(r)
        })

在这里插入图片描述

5.4.3 值传递实现

官方的then()在不指定成功的回调函数也可以继续向下执行

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          // reject('Error')
          resolve('OK')
        }, 1000)
      })

      p1.then()
        .then((v) => {
          console.log(222)
        })
        .then((v) => {
          console.log(333)
        })
        .catch((r) => {
          console.log(r)
        })

在这里插入图片描述

实现方法,与异常穿透类似,在没有成功的回调函数的时候一样指定一个成功的回调函数

// 定义 Promise 的 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this // 保存调用then的Promise对象

  ......

  // 没有传递成功的回调函数
  // 给一个默认的成功回调函数
  if (typeof onResolved !== 'function') {
    onResolved = value => {
      return value //将resolve中传递的值,即Promise的结果向后传递
    }
  }

  ......
}

测试:

      let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
          // reject('Error')
          resolve('OK')
        }, 1000)
      })

      p1.then()
        .then((v) => {
          console.log(222)
        })
        .then((v) => {
          console.log(333)
        })
        .catch((r) => {
          console.log(r)
        })

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第39张图片

5.5 resolve() 实现

// 传递的为Promise对象,则返回的Promise的状态由传入的决定
// 传入的为其他值,则返回的Promise对象为成功
Promise.resolve(value) {
  return new Promise((resolve, reject) => {
    if (value instanceof Promise) {
      // 为Promise对象,肯定可以调用then
      value.then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    } else {
      resolve(value)
    }
  })
}

测试:

      const p1 = Promise.resolve('OK')
      const p2 = Promise.resolve(
        new Promise((resolve, reject) => {
          resolve('OK~~~')
        })
      )
      const p3 = Promise.resolve(
        new Promise((resolve, reject) => {
          reject('err')
        })
      )
      console.log(p1)
      console.log(p2)
      console.log(p3)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第40张图片

5.6 reject() 实现

无论传递什么值都返回一个失败的Promise对象

Promise.reject = function(value) {
  return new Promise((resolve, reject) => {
    reject(value)
  })
}

测试:

      const p1 = Promise.reject('OK')
      const p2 = Promise.reject(
        new Promise((resolve, reject) => {
          resolve('OK~~~')
        })
      )
      const p3 = Promise.reject(
        new Promise((resolve, reject) => {
          reject('err')
        })
      )
      console.log(p1)
      console.log(p2)
      console.log(p3)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第41张图片

5.7 all() 实现

Promise对象数组中所有的都为成功返回的Promise对象才成功,有一个失败返回的就为失败。

Promise.all = function (promises) {
  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 记录状态为成功的promise对象个数
    let count = 0;
    // 保存成功promise对象的结果
    let arr = []
    for (let i = 0; i < promises.length; i++) {
      // Promise 对象肯定可以调用 then
      promises[i].then(v => {
        // 状态为成功的个数++
        count++
        // 保证数组中结果集的顺序与传入的promise对象的顺序一样
        arr[i] = v
        // 状态为成功的个数与promise对象数组的个数一样
        if (count === promises.length) {
          resolve(arr)
        }
      }, r => {
        reject(r)
      })
    }
  })
}

测试:

      const p1 = Promise.resolve('OK')
      const p2 = Promise.resolve(
        new Promise((resolve, reject) => {
          resolve('OK~~~')
        })
      )
      const p3 = Promise.reject(
        new Promise((resolve, reject) => {
          reject('err')
        })
      )
      const res1 = Promise.all([p1, p2])
      const res2 = Promise.all([p1, p2, p3])
      console.log(res1)
      console.log(res2)

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第42张图片

5.8 race()实现

最先改变状态的promise对象的状态为返回的Promise对象的状态,其结果为返回的Promise对象的结果。

Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      // 第一个改变状态的promise在其回调函数直接改变返回promise的回调函数
      promises[i].then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    }
  })
}
      const p1 = Promise.resolve(
        new Promise((resolve, reject) => {
          setTimeout(()=>{
            resolve('OK~~~')
          }, 1000)
        })
      )
      const p2 = Promise.resolve('OK')
      const p3 = Promise.reject(
        new Promise((resolve, reject) => {
          reject('err')
        })
      )
      const res1 = Promise.race([p1, p2, p3])
      console.log(res1)

在这里插入图片描述

5.9 then方法回调的异步执行

官方的then

      const p1 = new Promise((resolve, reject) => {
        resolve('OK')
        console.log(111)
      })
      p1.then((v) => {
        console.log(222)
      })
      console.log(333)

异步任务会在同步任务全部执行完成后才执行
在这里插入图片描述

我们的then

在这里插入图片描述

修改方法:(原先的回调函数均为同步执行的)将其修改为异步任务

    // 状态为成功
    if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
      setTimeout(() => {
        callback(onResolved)
      });
    }
    // 状态为失败
    if (this.PromiseState === 'rejected') {
      setTimeout(() => {
        callback(onRejected)
      });
    }
  // 定义resolve函数
  function resolve(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    setTimeout(() => {
      self.callback.forEach(item => { // 调用所有的回调函数
        item.onResolved(self.PromiseResult)
      })
    })
  }

  // 定义reject函数
  function reject(data) {
    if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
    self.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
    self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
    setTimeout(() => {
      self.callback.forEach(item => { // 调用所有的回调函数
        item.onRejected(self.PromiseResult)
      })
    })
  }

修改完成后
在这里插入图片描述

5.10 封装为Promise类

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第43张图片

class Promise {
  constructor(excutor) {
    // 定义 PromiseState PromiseResult 
    this.PromiseState = 'pending' // 默认状态 pending
    this.PromiseResult = null // 结果默认为空
    const self = this // 将 Promise 对象的 this 保存下来
    this.callback = [] // 声明一个数组用于保存回调函数

    // 定义resolve函数
    function resolve(data) {
      if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
      self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState
      self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
      setTimeout(() => {
        self.callback.forEach(item => { // 调用所有的回调函数
          item.onResolved(self.PromiseResult)
        })
      })
    }

    // 定义reject函数
    function reject(data) {
      if (self.PromiseState !== 'pending') return // 状态已经修改直接退出
      self.PromiseState = 'rejected'  // 修改 Promise的状态 PromiseState
      self.PromiseResult = data       // 修改 Promise的结果 PromiseResult
      setTimeout(() => {
        self.callback.forEach(item => { // 调用所有的回调函数
          item.onRejected(self.PromiseResult)
        })
      })
    }

    // 捕获 excutor 中的异常并进行处理
    try {
      // 调用传参传过来的执行器函数  同步调用
      excutor(resolve, reject)
    } catch (e) {
      // 处理异常,改变Promise状态为失败,改变结果
      reject(e)
    }
  }

  then(onResolved, onRejected) {
    const self = this // 保存调用then的Promise对象

    // 判断失败的回调函数
    // 由于报错造成的原因是失败的回调函数为undefined
    // 所以当失败的回调函数为未定义时候,补充一个失败回调
    // 让其报错
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }

    // 没有传递成功的回调函数
    // 给一个默认的成功回调函数
    if (typeof onResolved !== 'function') {
      onResolved = value => {
        return value //将resolve中传递的值,即Promise的结果向后传递
      }
    }

    // 执行完then()返回一个Promise对象
    return new Promise((resolve, reject) => {
      // 封装函数
      function callback(type) {
        try {
          const result = type(self.PromiseResult)
          if (result instanceof Promise) { // 如果是Promise的实例对象
            result.then(v => {
              resolve(v) // 调用成功函数,改变返回的Promise对象为成功
            }, r => {
              reject(r) // 调用失败函数,改变返回的Promise对象为失败
            })
          } else {
            resolve(result)
          }
        } catch (e) {
          reject(e)
        }
      }
      // 状态为成功
      if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') {
        setTimeout(() => {
          callback(onResolved)
        });
      }
      // 状态为失败
      if (this.PromiseState === 'rejected') {
        setTimeout(() => {
          callback(onRejected)
        });
      }
      // 状态为 pending
      if (this.PromiseState === 'pending') {
        this.callback.push({
          onResolved: function () {
            callback(onResolved)
          },
          onRejected: function () {
            callback(onRejected)
          }
        })
      }
    })
  }

  catch(onRejected) {
    // catch 方法中执行的是失败的回调函数
    // 与 then 差别为只有失败的回调函数,可以直接使用then
    return this.then(undefined, onRejected)
  }

  // resolve、reject、all、race不属于实例对象,属于类
  // 用static进行修饰

  static resolve(value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        // 为Promise对象,肯定可以调用then
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(value)
      }
    })
  }

  static reject(value) {
    return new Promise((resolve, reject) => {
      reject(value)
    })
  }

  static all(promises) {
    // 返回一个Promise对象
    return new Promise((resolve, reject) => {
      // 记录状态为成功的promise对象个数
      let count = 0;
      // 保存成功promise对象的结果
      let arr = []
      for (let i = 0; i < promises.length; i++) {
        // Promise 对象肯定可以调用 then
        promises[i].then(v => {
          // 状态为成功的个数++
          count++
          // 保证数组中结果集的顺序与传入的promise对象的顺序一样
          arr[i] = v
          // 状态为成功的个数与promise对象数组的个数一样
          if (count === promises.length) {
            resolve(arr)
          }
        }, r => {
          reject(r)
        })
      }
    })
  }

  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        // 第一个改变状态的promise在其回调函数直接改变返回promise的回调函数
        promises[i].then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      }
    })
  }
}

测试:

      const p1 = new Promise((resolve, reject) => {
        resolve('OK')
        console.log(111)
      })
      p1.then((v) => {
        console.log(222)
      })
      console.log(333)

在这里插入图片描述

6 async与await

6.1 mdn 文档

【async】
【await】

6.2 async 函数

  1. async函数的返回值为 promise 对象

            async function f1() {
    
    	    }
    	    const res1 = f1()
    	    console.log(res1)
    

    在这里插入图片描述

  2. promise 对象的结果由 async 函数执行的返回值决定(与then的规则一样)
    返回的为非Promise对象的数据,则函数返回的结果为成功的Promise对象,Promise对象的结果为return的结果

        async function f1() {
          return 123
        }
        const res1 = f1()
        console.log(res1)
    

    在这里插入图片描述

    返回的为失败的Promise,函数返回的为失败的Promise

        async function f1() {
          return new Promise((resolve, reject)=>{
            reject('OK')
          })
        }
        const res1 = f1()
        console.log(res1)
    

    在这里插入图片描述

    返回的为成功的Promise,函数返回的为成功的Promise

        async function f1() {
          return new Promise((resolve, reject)=>{
            resolve('OK')
          })
        }
        const res1 = f1()
        console.log(res1)
    

    在这里插入图片描述

    函数抛出错误,返回的为失败的Promise

        async function f1() {
          throw 'ERROR'
        }
        const res1 = f1()
        console.log(res1)
    

    在这里插入图片描述

6.3 await 表达式

  1. await 右侧的表达式一般为 promise 对象, 但也可以是其它的值,运算相关的也行

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

        async function f() {
          const p = Promise.resolve('OK')
          let res = await p
          console.log(res)
        }
        f()
    

    在这里插入图片描述

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

        async function f() {
          let res = await 20
          console.log(res)
        }
        f()
    

    在这里插入图片描述

  • 注意
    await 必须写在 async 函数中, 但 async 函数中可以没有 await

        await 20;
    

    在这里插入图片描述

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

        async function f() {
          const p = Promise.reject('ERROR')
          let res = await p
          console.log(res)
        }
        f()
    

    在这里插入图片描述

        async function f() {
          const p = Promise.reject('ERROR')
          try {
            let res = await p
          } catch (error) {
            console.log(error)
          }
        }
        f()
    

    在这里插入图片描述

6.4 async与await结合实践 – 读取文件

6.4.1 不基于Promise实现 – 回调地狱

const { log } = require('console')
const fs = require('fs')

// 会出现data变量名覆盖
fs.readFile('./content.txt', (err, data1) => {
  if (err) return err
  fs.readFile('./content.txt', (err, data2) => {
    if (err) return err 
    fs.readFile('./content.txt', (err, data3) => {
      if (err) return err
      log( data1+data2+data3 )
    } )
  })
})

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第44张图片

6.4.2 基于Promise

const { log } = require('console')
const fs = require('fs')
// util 中的 util.promisify() 可以对读取文件的方法进行封装
const util = require('util')

const myReadFile = util.promisify(fs.readFile)
// 读取文件
async function read() {
  let data1 = await myReadFile('./content.txt')
  let data2 = await myReadFile('./content.txt')
  let data3 = await myReadFile('./content.txt')
  log(data1 + data2 + data3)
}
read()

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第45张图片

使用async与await,也便于报错处理,不像fs回调那样每层都要独立的报错处理

const { log } = require('console')
const fs = require('fs')
// util 中的 util.promisify() 可以对读取文件的方法进行封装
const util = require('util')

const myReadFile = util.promisify(fs.readFile)
// 读取文件
async function read() {
  try {
    let data1 = await myReadFile('./content1111111111111.txt')
    let data2 = await myReadFile('./content.txt')
    let data3 = await myReadFile('./content.txt')
    log(data1 + data2 + data3)
  } catch (e) {
    log(e)
  }
}
read()

Promise(简介、基本使用、API、手写实现 Promise、async与await)_第46张图片

你可能感兴趣的:(前端学习,javascript,前端,html5,js)