@[toc]
Promise
概念
Promise 是异步编程的一种解决方案,比传统的解决方案回调函数, 更合理和更强大。ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象
作用
指定回调函数方式更灵活易懂。
解决异步 回调地狱 的问题。
回调地狱
当一个回调函数嵌套一个回调函数的时候
就会出现一个嵌套结构
当嵌套的多了就会出现回调地狱的情况
比如我们发送三个 ajax 请求
- 第一个正常发送
- 第二个请求需要第一个请求的结果中的某一个值作为参数
- 第三个请求需要第二个请求的结果中的某一个值作为参数
ajax({
url: '我是第一个请求',
success (res) {
// 现在发送第二个请求
ajax({
url: '我是第二个请求',
data: {
a: res.a, b: res.b },
success (res2) {
// 进行第三个请求
ajax({
url: '我是第三个请求',
data: {
a: res2.a, b: res2.b },
success (res3) {
console.log(res3)
}
})
}
})
}
})
Promise使用
new Promise(function (resolve, reject) {
// resolve 表示成功的回调
// reject 表示失败的回调
}).then(function (res) {
// 成功的函数
}).catch(function (err) {
// 失败的函数
})
对象的状态
Promise 对象通过自身的状态,来控制异步操作。Promise 实例具有三种状态。
异步操作未完成(pending)
异步操作成功(fulfilled)
异步操作失败(rejected)
这三种的状态的变化途径只有两种。
一旦状态发生变化,就凝固了,不会再有新的状态变化。这也是 Promise 这个名字的由来,它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。这也意味着,Promise 实例的状态变化只可能发生一次
一旦状态发生变化,就凝固了,不会再有新的状态变化。这也是 Promise 这个名字的由来,它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。这也意味着,Promise 实例的状态变化只可能发生一次。
因此,Promise 的最终结果只有两种。
异步操作成功,Promise 实例传回一个值(value),状态变为fulfilled。
异步操作失败,Promise 实例抛出一个错误(error),状态变为rejected。Promise.all
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
p的状态由p1,p2,p3 决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
Promise.race
Promise.race()
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
Generator 函数
概念
Generator 函数是 ES6 提供的一种异步编程解决方案
Generator 函数是一个状态机,封装了多个内部状态。
执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
基本语法
function *gen(){
console.log(1)
yield;
console.log(2)
yield;
console.log(3)
}
let g = gen()
g.next()
g.next()
g.next()
yield(产出)表达式是暂停执行的标记,而next方法可以恢复执行。
function *gen(){
yield 1;
yield 2;
}
let g = gen()
let res1 = g.next()
console.log(res1)
let res2 = g.next()
console.log(res2)
let res3 = g.next()
console.log(res3)
function *gen(){
let res1 = yield;
console.log(res1)
let res2 = yield;
console.log(res2)
}
let g = gen()
g.next("data-1")
g.next("data-2")
g.next("data-3")
异步流程
手动版本
function *gen(){
let res1 = yield ajax("1.json")
console.log(res1)
let res2 = yield ajax("2.json")
console.log(res2)
}
let g = gen()
g.next().value.then(data=>{
g.next(data).value.then(data=>{
g.next(data)
})
})
自动版本
function* gen() {
let res1 = yield ajax("1.json")
console.log(res1)
let res2 = yield ajax("2.json")
console.log(res2)
}
function AutoRun(gen) {
let g = gen();
function next(data) {
let res = g.next(data);
if (res.done) return
res.value.then(function (data) {
next(data);
});
}
next();
}
AutoRun(gen);
Class语法
类的写法
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age)
}
}
let obj = new Person("kerwin",100)
console.log(obj)
getter与setter
class List{
constructor(ele){
this.element = ele
}
get html(){
return this.element.innerHTML
}
set html(arr){
this.element.innerHTML = arr.map(item=>`<li>${
item}</li>`).join("")
}
}
let obj = new List(document.querySelector("#list"))
obj.html = ["aaa","bbb","cccc"]
静态属性和静态方法
class Person {
static name = "Person这个类"
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age)
}
static eat(){
console.log("eat")
}
}
let obj = new Person("kerwin",100)
console.log(Person.name)
Person.eat()
继承
ES6 规定,子类必须在
constructor()
方法中调用super()
,否则就会报错。这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用super()
方法,子类就得不到自己的this
对象。
class Person {
static name = "Person这个类"
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age)
}
static eat(){
console.log("eat")
}
}
class Student extends Person{
constructor(name,age,score){
super(name,age)
this.score = score
}
say(){
super.say()
console.log(this.score)
}
static eat(){
super.eat();
console.log("student eat")
}
}
let obj = new Student("kerwin",100,200)
console.log(obj)
obj.say()
Student.eat()
模块化
JavaScript 现在有两种模块。一种是 ES6 模块,简称 ESM;另一种是 CommonJS 模块,简称 CJS。
CommonJS 模块是 Node.js 专用的,与 ES6 模块不兼容。语法上面,两者最明显的差异是,CommonJS 模块使用require()
和module.exports
,ES6 模块使用import
和export
。
写法1:
export default A1
import a1 from "./1.js"
写法2:
export {
A1,A2}
import {
A1,A2} from "./1.js"
import {
A1 as a1,A2 as a2} from "./1.js"
import * as obj from "./1.js"
export function A1(){
console.log("A1")
}
export function A2(){
console.log("A2")
}
import {
A1,A2} from "./1.js"
import {
A1 as a1,A2 as a2} from "./1.js"
import * as obj from "./1.js"
混合写法:
export {
A1}
export default A2
import A2,{
A1} from "./1.js"