十三、Generator
简介
Generator 函数是 ES6 提供的一种异步编程解决方案。语法上,可以把它理解成一个状态机,封装了多个内部状态。在Generator 函数执行时会返回一个遍历器对象,可以一次遍历函数内的每一个状态。
关键词
星号,用来修饰函数(只能放在function关键词与函数名的中间位置),yield 用来定义状态(异步操作)
Generator函数的创建
定义Generator函数及状态的定义。
function * f(){//Generator函数
yield "播放";
yield "停止";
yield "快进";
}
Generator函数的返回值
注:Generator函数中for…of只能获取状态
function * f(){//Generator函数
yield "播放";
yield "停止";
yield "快进";
return "我是函数返回值";
}
let p=f();
// p.next();
// p.next();
// p.next();
// console.log(p.next()); //注:与遍历器不同的是Generator函数的next()可以获取到函数的返回值。
for(let item of p){//由于for...of是根据done的值来判断循环是否结束,因此,只会输出状态,不会输出返回值。
//console.log(item);
}
console.log(p.next());
Generator函数使用next方法传递参数
next方法传递的参数是给上一个yield赋值。同时执行上一个yield和当前yield之间的代码。
function * f() {
let a=yield "播放";
console.log("a="+a);
let b=yield "停止";
console.log("b="+b);
let c=yield "快进";
console.log("c="+c);
let d=yield "快退";
console.log("d="+d);
let e=yield "录音";
console.log("e="+e);
return "我是返回值";
}
let pp=f();
pp.next("我是传值a");
pp.next("我是传值b");
pp.next("我是传值c");
pp.next("我是传值d");
pp.next("我是传值e");
console.log(pp.next("我是传值return"));
十四、Promise对象
概念:
Promise对象,异步编程的一种解决方案。也称之为一个容器,里面保存着某个未来才会结束的事件(异步操作)的结果。在语法上,其从它可以获取异步操作的消息。
状态:
pending(进行中)、fulfilled(已成功)和rejected(已失败)
作用:
Promise为了取代回调函数
回调地狱案例:
$.get("http://xu.rypy.vip/type/getfirstType",(data)=>{
//console.log(data);
$.post("http://xu.rypy.vip/type/getsecondTypeByFirsttype",{firstId:data.typelist[2].category_id},(data2)=>{
//console.log(data2);
$.post("http://xu.rypy.vip/type/getThirdTypeBySecondtype",{secondId:data2.typelist[0].category_id},(data3)=>{
//console.log(data3);
$.post("http://xu.rypy.vip/type/getGoodsbyThirdtype",{thirdId:data3.typelist[3].category_id},(goodlist)=>{
console.log(goodlist);
})
})
});
});
使用
创建Promise对象,
new Promise((resolve,reject)=>{
if(true)resolve("成功!");
else reject("失败!");
});
获取状态值的方法
在Promise对象中如果存在设置多个状态,则哪一状态最先执行完成,哪一状态就是最终Primise的值。
1、封装一个Promise对象
function f() {
return new Promise((resolve,reject)=>{//创建了一个Promise对象的容器
//setTimeout方法,参数一是回调函数,参数二是延时时间,参数三是可以给参数一传值
// setTimeout(resolve,3000,"我是成功的值");
// setTimeout(reject,1000,"我是失败的值");
//自定义一个错误
// throw new Error("我是一个自定义错误!");
//代码运行时错误
// console.log(age);
// let age=20;
//resolve("我是成功值的设置");
reject("我是失败的结果!");
});
}
2、使用then方法,获取值
then方法的第一个参数(回调函数)获取Promise对象成功状态的值。
then方法的第二个参数(回调函数)可以获取Promise对象失败状态的值。(不推荐使用)
f().then((data)=>{//回调函数的形参就是成功的值
console.log(data);
},(err)=>{
console.log(err);
});
3、使用catch方法, 获取失败状态的值
获取Promise对象失败状态的值、也可以捕获代码中的运行时错误、也可以捕获用户自定义错误。
//形式一
f().catch((err)=>{
console.log(err);
});
//形式二:推荐使用
f().then(data=>console.log(data)).catch(err=>console.log(err.message));
注:then()方法和catch()方法都可以单独出现
4、使用finally方法,执行永久执行的语句
f().then(data=>console.log(data)).catch(err=>console.log(err)).finally(()=>console.log("我是永久执行的代码"));
Promise对象的实例方法
1、Promise.all([异步操作1,异步操作2…])
概念
同时执行多个异步操作,并且返回值是一个Promise对象。
规则:
1、当all方法执行的异步任务全部都是成功状态,则会将成功状态的值以数组的形式返回,封装为Promise对象。
2、当all方法中,存在失败状态的结果,则会返回执行最快的失败状态的结果。
let p1=Promise.resolve("我是成功一");
let p2=Promise.resolve("我是成功二");
// let p3=Promise.reject("我是失败的值一");
let p4=new Promise((resolve,reject)=>{
setTimeout(reject,5000,"我是失败的2")
});
let p5=new Promise((resolve,reject)=>{
setTimeout(reject,3000,"我是失败的3")
});
Promise.all([p1,p4,p5]).then(data=>console.log(data)).catch(err=>console.log(err));
2、Promise.race()
同时执行多个异步操作,返回值是一个Promise对象
规则:返回所有异步操作的状态结果最快的值,不区分成功还是失败
// let p1=Promise.resolve("我是成功一");
let p2=Promise.resolve("我是成功二");
// // let p3=Promise.reject("我是失败的值一");
// let p4=new Promise((resolve,reject)=>{
// setTimeout(reject,5000,"我是失败的2")
// });
let p5=new Promise((resolve,reject)=>{
setTimeout(reject,3000,"我是失败的3")
});
let p6=new Promise((resolve,reject)=>{
setTimeout(resolve,1000,"我成功的3")
});
Promise.race([p5,p6]).then(data=>console.log(data)).catch(err=>console.log(err));
Promise对象的链式操作
then方法的链式操作返回值是一个Promise对象,且状态是成功状态。
Promise.resolve("成功的值").then(data=>{
return data+"第一个then";
}).then(data2=>{
//console.log(data2);
return data2+"第二个then";
}).then(data3=>{
console.log(data3);
});
应用
解决回调地狱问题
$.get("http://xu.rypy.vip/type/getfirstType").then(data=>{
return $.post("http://xu.rypy.vip/type/getsecondTypeByFirsttype",{firstId:data.typelist[2].category_id});
}).then(data2=>{
return $.post("http://xu.rypy.vip/type/getThirdTypeBySecondtype",{secondId:data2.typelist[0].category_id});
}).then(data3=>{
return $.post("http://xu.rypy.vip/type/getGoodsbyThirdtype",{thirdId:data3.typelist[3].category_id});
}).then(data4=>console.log(data4));
十五、async 函数
介绍
async函数,本质就是Generator函数的语法糖。
async函数是将 Generator函数的星号(*)替换成async,将yield替换成await。
async函数返回一个Promise对象
async 可以单独修饰函数,但是await不能单独出现在普通函数中。
基本语法:
function f() {
return new Promise(resolve=>{
setTimeout(resolve,3000,"我是Promise成功!");
});
}
async function f1(params) {
let a = await f();
console.log(a);
}
f1();
async函数的返回值
默认返回一个Promise对象。
function f() {
return new Promise(resolve=>{
setTimeout(resolve,3000,"我是Promise成功!");
});
}
async function f1(params) {
let a = await f();
//console.log(a);
return "我是async函数的返回值";
}
console.log(f1());
获取成功或失败的值
async函数中的关键词await只能获取成功状态的值,如果需要获取失败状态的值,可以采用捕获。
async function f() {
let p=await Promise.resolve("我是Promise成功的值");
console.log(p);
let p1=await Promise.reject("我是失败的值");
}
f().catch(err=>{
console.log(err);
});
async函数处理失败状态的方式
局部捕获
async function f(){
let a=await Promise.resolve("我是成功1");
console.log(a);
let b=await Promise.resolve("我是成功2");
console.log(b);
let c=await Promise.reject("我是失败的值").catch(err=>console.log(err));
return "我是返回值";
}
f().then(data=>console.log(data));
代码块方式
代码块
try{
console.log(a);
let a=20;
}catch(err){//原始ES6的语法
console.log(err.message);
}
// catch{//ES2020的语法
// }finally{
// console.log("我是永久执行的块");
// }
console.log("aaaaaa");
代码块处理失败状态
async function f() {
try{
let p1=await Promise.reject("dddd");
//异常,错误
}catch(e){
console.log(e);
}
console.log("ssssss");
}
f()
优雅的方式处理
//方式三 优雅的处理async函数的错误。
思路:异常或错误的处理方式进行封装为to方法,此方法需要一个参数,参数是Promise对象类型,注:此方法规定了返回值类型为数组。
此方法对应有一个插件 await-to-js
注:优雅的处理async函数中的错误,如果是Promise对象容器中代码的错误,需要局部捕获或块级捕获
function to(p){
return p.then(data=>[null,data]).catch(err=>[err,null]);
}
async function f() {
let [err1,data1]=await to(Promise.resolve("我是成功!!"));
console.log(data1);
let [err2,data2]=await to(Promise.reject("我是失败!"));
console.log(err2);
console.log("sdfsdfsd");
}
f();
十六、ES6中的面向对象
类的定义
语法:class 类名 {}
//定义类,关键词class
class Furist{
}
//类的使用(类的实例化),关键词new
let f=new Furist();//f叫做类的引用
类中的结构
类中可以定义方法(函数),也可以定义属性。
类的方法
类中的方法包含3类,构造方法、成员方法、静态方法
构造方法
关键词constructor
语法:constructor(){}
class Fruit{
constructor(){//类的构造方法
}
}
成员方法
即一般普通的方法,
语法:方法名(参数){ }
class Fruit{
aa(params) {}
bb(){}
}
静态方法
语法:static 方法名(参数){}
class Fruit{
static aa(params) {}
static bb(){}
}
类方法的使用
class Friut{
constructor(str){
console.log("我是构造方法!"+str);
}
aa(){
console.log("我是成员方法!");
}
static bb(){
console.log("我是静态方法!");
}
}
//如果需要使用类,必须要先创建类的实例。
let f=new Friut();//创建了一个Friut类的实例
//构造方法,在创建类的实例的时候被调用。
let f1=new Friut("我是憨憨");
//上面new的变量名,专业术语叫 类的引用。
//成员方法只能使用引用来调用
f.aa();
//静态方法只能使用类名来调用
Friut.bb();
Friut.aa();
类的属性
类中的属性的分类 2类,成员属性,静态属性。
成员属性
语法:属性名即可,可以在成员方法/构造方法中使用 this.属性名
注:如果在成员方法中定义的成员属性,需要调用成员方法才可以赋值。如果是静态方法中定义的属性,也需要调用静态方法才可以赋值。
静态属性
语法:在静态方法中使用 this.属性名 ,也可以在类中使用关键词 static 属性名
class User{
interest="haha";
static username="rypy";
constructor(){
this.username="rypy1";
}
getPwd(){
this.pwd="123456";
}
static getSex(){
this.sex="男";
}
}
console.log(User.username);
User.getSex();
console.log(User.sex);
类的继承
类的继承 关键词 extends,语法:子类 extends 父类
**注:**ES6中类的继承,子类是完全继承父类的全部。
class Father{
firstName="A";
static secondName="F";
constructor(){
console.log("父类的构造方法");
}
getFirstName(){
return this.firstName;
}
static getSecondName(){
return this.secondName;
}
smoking(){
console.log("我吸烟");
}
}
class Son extends Father{
constructor(){
super();//调用父类的构造方法
console.log("我是子类的构造方法");
}
smoking(){//类的多态
super.smoking();//super.方法名可以调用父类的方法。
console.log("我不吸烟");
}
getFirstName(){
return{firstName:this.firstName}
}
}
let son=new Son();
// console.log(son.firstName);
// console.log(Son.secondName);
// console.log(son.getFirstName());
// console.log(Son.getSecondName());
// son.smoking();
console.log(son.getFirstName());
// let father=new Father();
// father.smoking();
super和this关键词
super关键词,用在子类中,指向父类的实例,且只能调用父类的方法(构造方法super(),是调用父类的构造方法。成员方法中,只能调用父类的成员方法,静态方法中,只能调用父类的静态方法)
this关键词,指向当前类
class Father{
firstName="A";
static secondName="F";
constructor(){
console.log("父类的构造方法");
}
getFirstName(){
return this.firstName;
}
static getSecondName(){
return this.secondName;
}
smoking(){
console.log("我吸烟");
}
static drinking(){
console.log("我喝酒");
}
}
class Son extends Father{
// constructor(){
// super();
// }
smoking(){
super.smoking();
console.log("子类打印");
}
static drinking(){
super.drinking();
this.drinking();
console.log("我不喝酒");
}
static drinking2(){
console.log("haha");
}
}
let son=new Son();
// son.smoking();
Son.drinking();