1.Promise设计的初衷:你需要用ajax进行多次请求的时候,如果每次请求都要依赖于上一次请求返回的数据作为参数,经过一层层的请求最终导致代码呈现阶梯状,代码的可读性非常差,不利于维护。如果请求C的需求依赖A和B的结果,但是请求A和B却相互独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑消耗了更多的等待时间;
这种结构称为回调地狱:回调函数层层嵌套,Promise对象能够使我们更合理,更规范地处理异步操作;
2.Promise的基本用法:
let pro = new Promise((resolve, reject) => {})
console.log(pro);
Promise对象是全局对象,也可以理解为一个类,创建Promise实例的时候,要有一个new关键字,参数是一个匿名函数,其中有两个参数:resolve(解决)和reject(拒绝),两个函数均为方法。
resolve方法用于处理异步操作成功后的业务,reject方法用于操作异步操作失败后的业务;
2.1 promise的三种状态
Promise对象有三种状态:1.pending:刚刚创建一个Promise实例的时候,表示的初始状态
2.fulfilled:resolve方法调用的时候,表示操作成功
3.rejected:reject方法调用的时候,表示操作失败
状态只能从初始化 -->成功 或者 初始化-->失败,不能逆向转换,也不能在成功fulfilled和失败rejected之间转换;
let pro = new Promise((resolve, reject) => {
if (3 === 3) {
resolve();
} else {
reject();
}
})
console.log(pro); //打印出来的promise实例化对象,其状态为fulfilled
2.2 Then方法
then()方法:用于绑定处理操作后的处理程序。
let pro = new Promise(function(resolve, reject) {
if (3 === 3) {
resolve();
} else {
reject();
}
})
console.log(pro); //打印出来的promise实例化对象,其状态为fulfilled
pro.then(function(res) {
console.log('AAA');
}, function(error) {
console.log('BBB');
})
//最后打印AAA
let pro = new Promise(function(resolve, reject) {
if (3 !== 3) {
resolve();
} else {
reject();
}
})
console.log(pro); //打印出来的promise实例化对象,其状态为fulfilled
pro.then(function(res) {
console.log('AAA');
}, function(error) {
console.log('BBB');
})
//最后打印BBB
2.3 Catch方法:处理操作异常的程序。
let pro = new Promise(function(resolve, reject) {
if (3 !== 3) {
resolve();
} else {
reject();
}
})
console.log(pro);
pro.catch((error) => {
console.log('aaa');
})
//最终打印aaa
let pro = new Promise(function(resolve, reject) {
if (3 == 3) {
resolve();
} else {
reject();
}
})
console.log(pro);
pro.catch((error) => {
console.log('aaa');
})
//什么也不打印
综上利用then方法处理操作成功,用catch方法用于处理操作异常。
pro.then((res) => {}).catch((error) => {})
let pro = new Promise(function(resolve, reject) {
let condition = true;
if (condition) {
//调用操作成功方法
resolve('操作成功'); //状态从pending到fulfilled
} else {
//调用操作异常方法
reject('操作失败'); //状态从pending到rejected
}
});
//用then处理操作成功,用catch处理操作异常
pro.then(function(res) {
console.log(res);
}).catch(function(error) {
console.log(error);
})
案例(纯复制粘贴)
let pro = newPromise(function(resolve, reject) {
if (true) {
//调用操作成功方法
resolve('操作成功');
} else {
//调用操作异常方法
reject('操作异常');
}
});
//用then处理操作成功,catch处理操作异常
pro.then(requestA)
.then(requestB)
.then(requestC)
.catch(requestError);
function requestA() {
console.log('请求A成功');
return '请求B,下一个就是你了';
}
function requestB(res) {
console.log('上一步的结果:' + res);
console.log('请求B成功');
return '请求C,下一个就是你了';
}
function requestC(res) {
console.log('上一步的结果:' + res);
console.log('请求C成功');
}
function requestError() {
console.log('请求失败');
}
//打印结果:
//请求A成功
//上一步的结果:请求B,下一个就是你了
//请求B成功
//上一步的结果:请求C,下一个就是你了
//请求C成功
案例中,先是创建一个实例,还声明了4个函数,其中三个是分别代表着请求A,请求
B,请求C;有了then方法,三个请求操作再也不用层层嵌套了。我们使用then方法,按照调用顺序,很直观地完成了三个操作的绑定,
并且,如果请求B依赖于请求A的结果,那么,可以在请求A的程序用使用return语句把需要的数据作为参数,传递给下一个请求,
案例中我们就是使用return实现传递参数给下一步操作的。
2.4 Promise.all方法
接受一个数组作为参数,数组的元素是Promise实例化对象,当参数中的实例对象的状态都为fulfilled的时候,promise.all()才有返回值
let pro1 = new Promise((resolve) => {
setTimeout(() => {
resolve('实例1操作成功')
}, 5000);
});
let pro2 = new Promise((resolve) => {
setTimeout(() => {
resolve('实例2操作成功')
}, 1000);
})
Promise.all([pro1, pro2]).then((result) => {
console.log(result) //等待5s后,打印 ["实例1操作成功", "实例2操作成功"]
})
2.5 Promise.race()方法:参数和Promise.all()参数一样,都是数组,只要有一个状态发生变化(不管是成功fulfilled还是失败refected),
他都有返回
let pro1 = new Promise((resolve) => {
setTimeout(() => {
resolve('实例1操作成功')
}, 5000);
});
let pro2 = new Promise((resolve) => {
setTimeout(() => {
resolve('实例2操作成功')
}, 1000);
})
Promise.race([pro1, pro2]).then((result) => {
console.log(result) //等待1s后,打印 "实例2操作成功"
})
2.6 ES7中的Async和/await
为什么会有Async/awai? Promise虽然跳出了异步嵌套的怪圈,解决了回调地狱的问题,用链式表达更加清晰,但是我们也发现
如果有大量的异步请求的时候,流程复杂的情况下,会发现充满了屏幕的then,看起来非常吃力,而ES7的Async/Await的出现就是为了解决这种复杂的情况;
Async/await的基本使用:他是基于generator函数做的语法糖。async用于申明一个function是异步的(js中常见的异步:计时器和回调函数),
返回的是一个promise对象,而await可以认为是async wait的简写,等待一个异步方法执行完成,async必须声明的是一个function,await必须在声明函数内部使用。
//async 用于声明一个function是异步的,返回一个promise对象;
async function demo() {
setTimeout(() => {
console.log('我是async声明的异步函数');
}, 1000);
return '我是async声明的异步函数的返回值'
}
demo()
console.log(demo());
demo().then(res => {
console.log(res);
})
打印结果,自己调试;
Async/await的应用
function sleep(wait) {
return new Promise((res, rej) => {
setTimeout(() => {
res(wait)
}, wait);
})
}
sleep(100).then(result => {
return sleep(result + 100)
//返回一个新的Promise类型的对象,后面继续执行then方法
}).then(result2 => {
return sleep(result2 + 100)
}).then(result3 => {
console.log(result3);
})
后面的结果都是依赖前面的结果,await是强制把异步变成了同步,这一句代码执行完,才会执行下一句。
function sleep(wait) {
return new Promise((res, rej) => {
setTimeout(() => {
res(wait)
}, wait);
})
}
async function demo() {
let result1 = await sleep(100);
let result2 = await sleep(result1 + 100);
let result3 = await sleep(result2 + 100);
return result3;
}
demo().then(res => {
console.log(res);
})
2.类的使用
2.1 类的属性和方法
声明一个类的写法:
class Animal{
constructor(color){
this.color = color;
}
}
this指向:指向的是该类实例化后的对象
2.2类的实例化对象
给类添加属性和方法:
class Animal {
constructor(color) {
this.color = color;
}
getName(){
return this.name;
}
}
2.3 类的实例
class Animal {
constructor(name) {
this.name = name;
}
getName() {
return `This is a ${this.name}`;
}
}
let dog = new Animal('dog');
console.log(dog.name); //dog
console.log(dog.getName()); //This is a dog
实例对象的创建注意事项: 必须使用new关键字来创建类的实例化对象;先声明定义类,再创建实例,否则会报错;
2.4 类的继承:在es6中使用extends关键字来实现子类继承父类
class Animal {
constructor(name) {
this.name = name;
console.log(this);
}
getName() {
return `This is a ${this.name}`;
}
}
class Dog extends Animal {
constructor(name, color) {
super(name);
this.color = color;
}
getAttritube() {
return `${super.getName()},
name: ${this.name},
color: ${this.color}`
}
}
let dog = new Dog('dog', 'red');
console.log(dog.name); //dog
console.log(dog.getAttritube());
//This is a dog,
//name: dog,
//color: red
定义了两个类,Animal类作为父类,Dog类作为子类,然后通过关键字extends来是实现继承,此外,还有一个关键字super,相当于父类中的this,可以用super来引用父类,来访问父类,super后面不再赋值,因为是继承父类中的属性或者方法,已经默认是父类中的属性或者方法了。
3.Module模块;
es6的module模型转换成es5:
1:vscode安装live sever;
2.<script type="module">将script便签中的type类型换成module,告诉浏览器我们要使用es6的模块化了。
3.1模块module:一个模块,就是一个对其他模块暴露自己的属性或者方法的文件。
3.2导出Export:作为一个模块,可以选择性地给其他模块暴露自己的属性和方法,供其他模板使用;
3.3导入import:作为一个模块,可以根据需要,引入其他模块提供的属性和方法,供自己模板使用;
3.4模板化的实现:
需要导出的模板js
export let name = '张三';
需要导入的模板js
import {name} from '' //引号里面是导出模板js的路径