🌈ES6 —— Promise 与 Class 类
⭕ES6 —— Promise
🔔Promise 是什么?
🐼概念
Promise是异步操作的一种解决方案
🐼什么时候使用 Promise
Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题
🔔Promise 的基本用法
🐼1.实例化构造函数生成实例对象
1
| const p = new Promise(()=>{})
|
🐼2.Promise 的状态
1 2 3 4 5 6 7 8 9 10 11 12 13
| const p = new Promise((resolve, reject)=>{ reject(); }); console.log(p);
|
🐼3.then() 方法
1 2 3 4 5
| p.then(()=>{ console.log('执行已成功的回调'); },()=>{ console.log('执行已失败的回调'); });
|
🐼4.resolve 和 reject 函数的参数
1 2 3 4 5 6 7 8 9 10 11 12
| const p = new Promise((resolve,reject)=>{ reject(new Error('错误信息')); }) p.then( data=>{ console.log('success',data); }, err=>{ console.log('error',err); } );
|
🔔Promise实例方法 —— then() 方法
🐼1.什么时候执行
pending –> fulfilled 时,执行 then 的第一个回调函数
pending –> rejected 时,执行 then 的第二个回调函数
🐼2.执行后的返回值
then 方法执行后返回一个新的 Promise 对象
🐼3.then 方法返回的 Promise 对象的状态改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const p = new Promise((resolve,reject)=>{ reject(new Error('错误信息')); }); p.then( data=>{ console.log('succ1',data); }, err=>{ console.log('err1',err); return undefined; return new Promise(resolve=>{ resolve(undefined); }) } ).then( data=>{ console.log('succ2',data); }, err=>{ console.log('err2',err); } )
|
🔔Promise实例方法 —— catch() 方法
🐼1.catch() 方法的作用
很少用到 then() 方法的完整写法,通常只用 then() 方法的第一个回调;于是 catch() 是专门用来处理 rejected状态的 —> 本质就是 then() 方法的一个特例:
then(null,err=>{});
🐼2.基本用法
1 2 3 4 5 6 7 8 9
| new Promise((resolve, reject)=>{ reject('reason'); }) .then(data=>{ console.log(data); }) .catch(err=>{ console.log(err); });
|
catch() 可以捕获它前面的错误
一般总是建议,Promise 对象后面要跟 catch() 方法,这样可以处理 Promise 内部发生的错误
🔔Promise实例方法 —— finally() 方法
🐼1.什么时候执行
当 Promise 状态发生变化时,,不论如何变化都执行,不变化不执行
🐼2.本质
finally() 本质上是 then() 的特例
1 2 3 4 5 6 7 8 9 10 11 12 13
| new Promise((resolve, reject)=>{ resolve('succ'); reject('err') }) .then(data=>{ return data; }) .catch(err=>{ return new Promise((resolve, reject)=>{ reject(err); }) });
|
🔔Promise 构造函数的方法:Promise.resolve() 和 Promise.reject()
🐼1.Promise.resolve()
是成功状态 Promise 的一种简写形式
1 2 3
| new Promise(resolve=>resolve('succ'));
Promise.resolve('succ');
|
🐼2.参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| Promise.resolve('succ').then(data=>{ console.log(data); });
const p1 = new Promise(resolve=>{ setTimeout(resolve,1000,'我执行了'); }); Promise.resolve(p1).then(data=>{ console.log(data); });
p1.then(data=>{ console.log(data) }); console.log(Promise.resolve(p1) ==== p1);
const obj = { then(){ console.log('then'); } }
Promise.resolve(obj).then( data=>{ console.log(data); }, err=>{ console.log(err); } );
|
🐼2.Promise.reject()
失败状态 Promise 的一种简写形式
1 2 3 4 5 6 7 8
| new Promise((resolve, reject)=>{ reject('reason'); });
Promise.reject('reason');
|
🔔Promise 构造函数的方法 —— Promise.all()
🐼1.有什么用
Promise.all() 关注多个 Promise 对象的状态变化
传入多个 Promise 实例,包装成一个新的 Promise 实例返回
🐼2.基本用法
Promise.all() 的状态变化与所有传入的 Promise 实例对象状态有关
所有状态都变成 resolved,最终的状态才会变成 resolved;
只要有一个变成 rejected,最终的状态就变成 rejected
🔔Promise 构造函数的方法 —— Promise.race()
🐼1.有什么用
Promise.race() 关注多个 Promise 对象的状态变化
传入多个 Promise 实例,包装成一个新的 Promise 实例返回
🐼2.基本用法
Promise.race() 的状态取决于第一个完成的 Promise 实例对象,如果第一个完成的成功了,那最终就成功;如果第一个完成的失败了,那最终就失败
🔔Promise 构造函数的方法 —— Promise.allSettled()
🐼1.有什么用
Promise.allSettled() 关注多个 Promise 对象的状态变化
传入多个 Promise 实例,包装成一个新的 Promise 实例返回
🐼2.基本用法
Promise.allSettled() 的状态与传入的 Promise 状态无关
永远都是成功的
它只会忠实的记录下各个 Promise 的表现
🔔Promise 构造函数的方法 —— Promise.any()
🐼返回值及用法
参数中只要有一个 Promise 改变为成功状态,则返回的 Promise 状态就是成功的状态
如果参数中所有的 Promise 状态均为失败状态,则返回的 Promise 状态就是失败的状态
注意事项:
Promise.any() 不会因为某个 Promise 实例变成失败状态而结果,这个方法用于返回第一个成功的 Promoise
只要有一个 Promise 成功,此方法就会终止,它不会等待其他 Promise全部完成
💡Promise 的注意事项
🐼1.resolve 或 reject 执行后的代码
1 2 3 4 5 6
| new Promise((resolve, reject)=>{ return resolve('succ'); console.log('hello'); 会被执行,但不符合书写习惯,不建议× });
|
🐼2.Promise.all/race/allSettled 的参数问题
参数如果不是 Promise 数组,会将不是 Promise 的数组元素转变为 Promise 对象
不只是数组,任何可遍历的都可以作为参数
数组,字符串,Set,Map,NodeList,arguments
🐼2.Promise.all/race/allSettled 的错误处理
错误既可以单独处理,也可以统一处理
一旦被处理,就不会在其他地方再处理一遍了
💡Promise 的应用 —— 异步加载图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Promise异步加载</title> <style> img { width: 100px; margin: 100px auto; display: block; } </style> </head> <body> <img src="https://imgblog.yubai.eu.org/红灯.png" alt="" /> <script>
const loadImgAsync = url => { return new Promise((resolve, reject) => { const img = new Image(); img.addEventListener('load', () => { resolve(img); }); img.addEventListener('error', () => { reject(new Error(`Cloud not load img at ${url}`)); }); img.src = url; }); };
const imgDom = document.querySelector('img');
loadImgAsync('https://imgblog.yubai.eu.org/绿灯.png') .then(img => { imgDom.src = img.src; }) .catch(err => { console.log(err); }); </script> </body> </html>
|
💡async/await
🐼1.什么是async/await
async/await是基于Promise实现的
async/await使得异步代码看起来像同步代码
以前的方法有回调函数和Promise,async/await是写异步代码的新方式
🐼2.async/await语法
async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,在接着执行函数体内后面的语句。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const timeout= time => { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(); }, time); }) }; const start = async () => { console.log('start'); await timeout(3000); console.log('end'); return "imooc" }; start().then(()=> { console.log('test....'); });
|
🐼3.注意事项
1、await 命令只能在 async 函数之中,如果用在普通函数,就会报错!
2、await 后面跟着是一个 Promise 对象,会等待 Promise 返回结果了,再继续执行后面的代码
3、await 后面跟着的是一个数值或者字符串等数据类型的值,则直接返回该值
4、await后面跟着的是定时器,不会等待定时器里面的代码执行完,而是直接执行后面的代码,然后再执行定时器中的代码
🐼4.错误捕获
可以直接用标准的 try catch的语法捕获错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const timeout = time => { return new Promise(function (resolve, reject) { setTimeout(function () { reject('error'); }, time); }) }; const start = async () =>{ try { console.log('start'); await timeout(3000);
console.log('end'); } catch (err) { console.log(err); } }; start()
|
⭕ES6 —— Class类
🔔Class 是什么?
🐼1.概念
类可以看做是对象的模板,用一个类可以创建出许多不同的对象
🐼2.基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Person { constructor(name, age){ this.name = name; this.age = age;
} speak(){ console.log('speak'); } }
const p = new Person('zhangsan', 19);
|
🔔Class的两种定义形式
🐼1.声明形式
1 2 3 4 5
| class Person { constructor(){} speak(){} } new Person();
|
🐼2.表达式形式
1 2 3 4 5 6 7 8 9
| const Person = class{ constructor(){} speak(){} }
new (class{ constructor(){} speak(){} })();
|
🔔实例属性、静态方法、静态属性
🐼1.实例属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Person { age = 18; sex = 'male'; getGender = function() { console.log(this.name); }; constructor(name, sex) { this.name = name; this.sex = sex; } } const p = new Person('zhangsan', 'woman'); console.log(p.name); console.log(p.age); console.log(p.sex); p.getGender();
|
🐼2.静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Person { constructor() {} speak() { console.log('speak'); console.log(this); } static speak() { console.log('static speak'); console.log(this); } }
const p = new Person(); p.speak(); Person.speak();
|
🐼3.静态属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Person { constructor(name) { this.name = name; }
static getVision() { return '1.0'; }
}
const p = new Person('zhangsan');
console.log(Person.getVision());
|
🔔私有属性和方法
🐼1.为什么需要私有属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13
|
class Person { constructor(name) { this.name = name; } speak() { console.log('speak'); } } const p = new Person('zhangsan'); console.log(p.name); p.speak();
|
🐼2.模拟私有属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Person { constructor(name) { this._name = name; } speak() { console.log('speak'); }
getName() { return this._name; } } const p = new Person('zhangsan'); console.log(p.name); console.log(p.getName()); p.speak();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
(function () { let name; class Person { constructor(username) { name = username; } getName() { return name; } }
window.Person = Person; })(); (function () { const p = new Person('zhangsan'); console.log(p.name); console.log(p.getName()); })();
|
🔔继承 —— extends
🐼1.子类继承父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Person { constructor(name, age) { this.name = name; this.age = age;
this.say = function () { console.log('say'); }; } speak() { console.log('speak'); } static speak() { console.log('static speak'); } } Person.vision = '1.0';
class Student extends Person { constructor(name, age) { super(name, age); } }
const stu = new Student('zhangsan', 19); console.log(stu.name); console.log(stu.age); stu.say(); stu.speak(); Student.speak(); console.log(Student.vision);
|
🐼2.改写继承的属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class Person { constructor(name, age) { this.name = name; this.age = age;
this.say = function () { console.log('say'); }; } speak() { console.log('speak'); } static speak() { console.log('static speak'); } } Person.vision = '1.0';
class Student extends Person { constructor(name, age, gender) { super(name, age);
this.gender = gender; } speak() { console.log('Student speak'); } static speak() { console.log('static Student speak'); } hello() { console.log('hello'); } }
const stu = new Student('zhangsan', 19, '男'); console.log(stu.name); console.log(stu.age); console.log(stu.gender); stu.say(); stu.speak(); stu.hello(); Student.speak(); console.log(Student.vision);
|
🔔继承 —— super
🐼1.作为函数调用
代表父类的构造方法,只能用在子类的构造方法中,用在其他地方就会报错
super 虽然代表了父类的构造方法,但是内部的 this 指向子类的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Person { constructor(name, age) { this.name = name; this.age = age;
console.log(this); } speak() { console.log('speak'); } }
class Student extends Person { constructor(name, age) { super(name, age); } }
new Student('zhangsan', 19);
|
🐼2.作为对象使用
📍2.1 在构造方法中使用或一般方法中使用
super 代表父类的原型对象 父类.prototype
所以定义在父类实例上的方法和属性,是无法通过 super 调用的
通过 super 调用父类的方法,方法内部的 this 指向当前的子类实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Person { constructor(name, age) { this.name = name; this.age = age; } speak() { console.log('speak'); console.log(this); } }
class Student extends Person { constructor(name, age) { super(name, age); console.log(super.name); super.speak(); } }
new Student('zhangsan', 19);
|
📍2.在静态方法中使用
super 指向父类,而不是父类的原型对象
通过 super 调用父类的方法时,方法内部的 this 指向当前的子类,而不是子类的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| static speak() { console.log('Person speak'); console.log('this'); }
static speak(){ super.speak(); console.log('Student speak'); }
Student.speak();
|
🐼3.注意事项
使用 super 的时候,必须显式指定是作为函数还是作为对象使用,否则会报错