ES6之 Promise 和 Class

本文详细介绍了JavaScript的同步与异步任务、宏任务与微任务、事件轮询机制,以及Promise的原理、基本用法、状态转换、then、catch和finally方法。通过实例解析了Promise的应用,包括解决回调地狱、处理异步操作的灵活性以及错误处理。同时,文章还探讨了Class的特性,如构造函数、静态方法和属性、继承和super关键字的使用。
摘要由CSDN通过智能技术生成

一、 异步 和 单线程

  • 同步:必须等待上一步执行完毕后,下一步才可以执行
  • 异步:在等待上一步执行的同时,可以进行其他处理
  • 进程:程序的一次执行,它占有一片独有的内存空间
  • 线程:CPU的基本调度单位,是程序执行的一个完整流程
  • JS是单线程的

1. 同步任务和异步任务

1. 同步任务

  • 非耗时任务,指主线程上排队执行的任务
  • 同步会阻塞代码执行
  • 只有前一个同步任务执行完成,才能进行下一个同步任务
  • 构造函数属于同步任务
    2. 异步任务
  • 耗时任务,指由js委托给**宿主环境**(js的执行环境,如浏览器、node.js等)进行执行
  • 异步不会阻塞代码
  • 当异步任务执行完成后,会通知JavaScript主线程执行异步任务的**回调函数 callback**

2.宏任务和微任务

异步任务 分为宏任务和微任务

2.1 宏任务

  • 异步Ajax请求
  • setTimeout、setInterval
  • DOM 事件监听
  • 文件操作
  • 其他宏任务
  • 宏队列:用来存放宏任务的容器

2.2 微任务

  • Promise.then、.catch、.finally
  • process.nextTick
  • async、await
  • 其它微任务
  • 微队列:用来存放微任务的容器

2.3 执行顺序

  • 页面第一次渲染:初始化同步代码 ==> 所有的微任务 ==> 渲染界面 ==> 执行第一个宏任务 ==> 所有的微任务 ==> 渲染界面 ==> 执行第一个宏任务
  • 界面更新渲染:所有的微任务 ==> 界面渲染 ==> 第一个宏任务

3. 事件轮询机制(event loop,异步实现的原理)

  • JS是通过事件轮询机制来实现单线程异步的
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

二、Promise

1. 认识 Promise

  • Promise是一种异步操作的解决方法
  • Promise之前解决异步的常用方式:回调函数
  • Promise 可以解决回调地狱问题(可阅读性差,任然需要回调,但是不会嵌套)
  • Promise指定回调的时机更加灵活(可以指定在异步操作启动后或完成后)

2. Promise 的基本用法

2.1 实例化构造函数生成实例对象

  • 在 new 的时候必须指定回调函数,否则会报错
  • 该回调函数接收两个参数:resolve、reject,这两个参数也是回调函数,resolve是成功时的回调,reject是是失败的回调
    const p = new Promise((resolve,reject) => {
      // 回调函数
    })
  • promise中可以不写具体逻辑,只需要写明何时调用resolve 或 reject

2.2 promise 的状态

  • pending:进行中
  • fulfilled / resolved:成功
  • rejected:失败

状态的改变不可逆,只能从进行中变为成功或失败

  • 不调用resolve或reject时,是pending状态
    const p = new Promise((resolve,reject) => {
      // 回调函数
    })
    console.log(p) 

在这里插入图片描述

  • 调用resolve()时,会由pending 变为 fulfilled
    const p = new Promise((resolve,reject) => {
      // 回调函数
      resolve()
    })
    console.log(p)

在这里插入图片描述

  • 调用reject时,会由 pending 变为 rejected
    const p = new Promise((resolve,reject) => {
      // 回调函数
      reject()
    })
    console.log(p)

在这里插入图片描述

2.3 then方法

  • then方法有两个回调函数,一个成功、一个失败
    p.then(() => {
      // 成功的回调
      console.log('成功')
    },() => {
      // 失败的回调
      console.log(('失败'))
    })

2.4 resolve 和 reject 函数的参数

  • 在创建 Promise调用resolve或reject的时候,可以进行传参
  • 传递参数在then对应的回调中可以接收
    const p = new Promise((resolve,reject) => {
      // 失败
      reject(new Error('falied'))
    })
    p.then(() => {
      // 成功的回调
      console.log('成功')
    },(err) => {
      // 失败的回调
      console.log(err)
    })

3. Promise 的实例方法

3.1 then()

  • Promise状态由 pending ==》 fulfilled 时,执行then的第一个回调函数(成功的回调)
  • Promise状态由 pending ==》 rejected时,执行then的第二个回调函数(失败的回调)

  • then 的回调函数中,return的是Promise包装后的

  • then 方法执行后会返回一个新的 Promise 对象

  • 该新 Promise 对象的状态是由 then 方法指定,如果不指定默认是 fulfilled(成功状态)

  • 如果要指定成功的参数,直接写在 then方法回调函数的return后即可

  • 如果要指定失败的参数,可以在return后面新建一个 Promise

    const p = new Promise((resolve,reject) => {
      // 成功
      resolve('调用成功!!')

      // 失败
      // reject(new Error('falied'))
    })
    
    p.then((data) => {
      // 成功的回调
      console.log(data)
      // 返回成功的Promise
      // return 'then方法成功的返回'
      
      // 返回失败的Promise
      return new Promise((resolve,reject) => {
        reject('then方法中返回失败的回调')
      })
    },(err) => {
      // 失败的回调
      console.log(err)
    }).then((data) => {
      console.log(data);
    },(err) => {
      console.log(err);
    })

3.2 catch()

  • then 既可以处理成功,也可以处理失败状态
  • 一般开发中,then 用于处理成功的状态
  • catch 用于处理失败的状态
    new Promise((resolve,reject) => {
      // resolve('成功')

      reject('失败')
    }).then(data => {
      console.log(data);
    }).catch(err => {
      console.log(err);
    })
  • catch 可以捕获它前面的错误
  • 一般建议在Promise对象后跟一个catch方法,用于捕获Promise的内部错误

3.3 finally()

  • 当Promise状态发生变化,不管什么变化都会执行 finally

3. Promise 的构造函数方法

3.1 Promise.resolve() 和 Promise.reject()

3.1.1 Promise.resolve()
  • Promise.resolve() 是成功状态 Promise 的简写
    // 完整写法
    new Promise(resolve => {
      resolve()
    })
    
    // 简写
    Promise.resolve()
  • Promise.resolve() 的参数
    • 一般参数
    • 参数为 Promise对象
    • 当参数为Promise对象时,直接返回这个Promise,不会进行其他处理
    • 当resolve 接收的是Promise对象时,后面的then会根据传递的Promise对象的状态变化决定执行哪一个回调
    • 参数为:具有 then 方法的对象
3.1.2 Promise.reject()
  • 失败状态的简写
  • Promise.reject()不管哪种参数,都会原封不动向后传递,作为后续方法的参数

3.2 Promise.all()

Promise.all ([ Promise1,Promise2,… ])

  • 关注多个Promise 对象的状态变化
  • 传入多个 Promise 实例,然后包装成一个新的 Promise实例进行返回
  • 只有需要包装的多个Promise实例状态都为成功,新的Promise状态才为成功(等待机制)

3.3 Promise.race()

Promise.race([promise1,promise2,…])

  • 关注多个Promise 对象的状态变化
  • 传入多个 Promise 实例,然后包装成一个新的 Promise实例进行返回
  • 新 Promise的状态取决于第一个完成的Promise对象,如果第一个完成的成功了,那最终就成功;如果第一个成功的状态是失败,那最终的就是失败
  • 只要其中任何一个异步完成,就会立即执行下一步的.then()操作(赛跑机制)

3.4 Promise.allSettled()

  • 该方法的状态与 Promise 状态无关,永远都是成功的
  • 它只会记录下各个 Promise的表现

4. Promise 的注意事项

  1. 推荐在调用 resolve 或 reject 的时候加上return,避免再去执行其后的代码
  2. Promise.all / race / allSettled 的参数如果不是数组形式,会被自动转为数组
  3. Promise.all / race / allSettled 的参数是任何 可遍历的

5. Promise应用 —— 异步加载图片

    const loadImgAsync = url => {
      return new Promise((resolve,reject) => {
        const img = new Image()
        // 图片加载成功
        img.onload = () => {
          resolve(img)
        }

        // 图片加载失败
        img.onerror = () => {
          reject(new Error(`Could not load image at ${url}`))
        }

        // 加载图片
        img.src = url
      })
    }

    // 获取图片的DOM元素
    const imgDOM = document.getElementById('img')
    loadImgAsync('http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-04-15/dfc11bb0-4af5-4e9b-9458-99f615cc685a.jpg').then(img => {
      // 替换原来的src
      imgDOM.src = img.src
    }).catch(err => {
      console.log(err)
    })

二、 Class

1. 初识 class

1.1 class是什么

语法:

class 类名 {
	// 构造方法
	constructor(){}
}
  • 类名的首字母一般大写
  • 实例化类的时候会执行构造方法(constructor),可以不写构造方法(浏览器会自动补全)
  • 构造方法中一般是类的属性,方法一般不写在构造函数中
  • 类中的公用方法,一般定义在构造方法外部,语法:方法名() {}
  • 公用方法中要使用构造方法中的属性时:this.属性名
  • 类中方法与方法之间没有逗号分隔
  • 类只能通过 new 来实例化
    class Person {
      constructor(name,age) {
        this.name = name
        this.age = age
      }
      // 公用的方法
      sayHi() {
        console.log(`大家好!我是${this.name},今年${this.age}岁!`)
      }
    }

    // 实例化类
    const dudu = new Person('嘟嘟',18)
    dudu.sayHi()

1.2 class 和 构造函数

构造函数Class
function 函数名(属性1,…) { }class 类名 { constructor(属性1,…){ } }
公用方法一般写在原型上: 函数名.prototype.公用方法名公用方法和构造方法constructor平级:公用方法名() {}
  • Class 的本质也是函数

1.3 Class的定义

1.3.1 声明式的定义
class 类名 {
	// 构造方法
	constructor(){}
}
1.3.2 表达式的定义
    const 类名 = class {
      constructor() {}
    }

2. Class 的属性和方法

2.1 实例属性

  • 构造方法(constructor )中的属性就是实例属性
  • 构造方法中的 this 指向实例对象
  • 一般会在类中,构造方法constructor 前,列出所有的实例属性并设置默认值,这样便于观察

2.2 静态方法

  • 静态方法就是类的方法
  • 之前和constructor 平级写的公用方法属于实例方法,实例方法需要实例化类后才可以调用
  • 静态方法不需要实例化就可以调用
  • 语法 :static 方法名 () {},调用:类名.方法名()
  • 实例方法中的this指向实例对象
  • 静态方法指向的是类本身,而不是实例对象

2.3 静态属性

  • 静态属性即类的属性
  • 语法:类的外部 类名.属性名 = 属性值 (不推荐)
  • 可以将静态属性改写静态方法的形式,最终返回需要的属性值
  • 静态属性的调用 : 类名.属性名

2.4 私有属性和方法

  • 只能在类的内部使用的属性和方法
  • 一般情况下,类的属性和方法都是公开的
  • 目前没有对应的私有属性和方法的语法,但可以模拟私有属性和方法
    • _ 开头表示私有
    • 将私有的属性和方法从类中移出

3. Class 的继承

3.1 子类继承父类 extends

  • 子类可以通过 extends 关键字实现对父类的继承
  • 类都有构造方法,在子类的构造方法中需要调用父类的构造方法: super()
  • 子类会继承父类的全部属性和方法
    // 父类
    class Person {
      // 构造方法
      constructor(name,age) {
        this.name = name
        this.age = age
        // 每创建一个实例就会创建一个该方法,不推荐这种写法,容易造成浪费
        this.sport = function() {
          console.log(`${name}经常运动~~~`)
        }
      }
      // 公用的方法
      sayHi() {
        console.log(`大家好!我是${this.name},今年${this.age}岁!`)
      }
      // 静态方法
      static study() {
        console.log(`${name}喜欢学习!`)
      }
    }
    // 父类的静态属性
    Person.nationality = '中国'

    // 子类
    class Programmer extends Person {
      constructor(name,age) {
        // 调用父类的构造方法
        super(name,age)
      }
    }


    // 实例化子类
    const dudu = new Programmer('嘟嘟',24)
    dudu.sayHi()
    dudu.sport()
    Programmer.study()
    console.log(Programmer.nationality)
  • 子类可以改写继承的属性和方法
  • 子类还可以定义自己特有的属性和方法
  • 同名覆盖原则,子类的属性和方法和父类同名,则子类的会覆盖父类的
  • 子类如果要添加自己的属性,则要写在super 后面!!!

3.2 super

  • super既可以作为函数调用,也可以作为对象使用
3.2.1 super作为函数调用
  • 代表调用父类的构造方法,只能用在子类的构造方法中,用在其他地方会报错
  • 但此时 super 中的 this 指向子类的实例对象
3.2.2 super 作为对象使用
  1. 在构造方法或一般方法中使用
  • 代表父类原型对象,故定义在父类实例上的属性或方法,无法通过super调用
  • 通过 super 调用父类的方法时,方法内部的 this 指向当前子类的实例对象
  1. 在静态方法中使用
  • 代表父类,而不是父类的原型对象
  • 通过 super 调用父类方法时,方法内部的 this 指向当前的子类,而不是子类的实例对象
3.2.3 注意事项
  • 使用 super 时,必须显示指定是作为函数还是对象使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值