【前端】ES6:Promise对象和Generator函数
文章目录
- 1 Promise对象
- 1.1 回调地狱
- 1.2 Promise使用
- 1.3 Promise对象的状态
- 1.4 Promise.all
- 1.5 Promise.race
- 2 Generator函数
- 2.1 基本语法
- 2.2 异步流程
- 2.2.1 手动版本
- 2.2.2 自动版本
1 Promise对象
Promise是异步编程的一种解决方案,比传统的解决方案回调函数,更合理和更强大。
ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象 。
- 指定回调函数方式更灵活易懂。
- 解决异步 回调地狱 的问题。
1.1 回调地狱
当一个回调函数嵌套一个回调函数的时候,就会出现一个嵌套结构,当嵌套的多了就会出现回调地狱的情况。
比如我们发送三个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)
}
})
}
})
}
})
1.2 Promise使用
new Promise(function (resolve, reject) {
// resolve 表示成功的回调
// reject 表示失败的回调
}).then(function (res) {
// 成功的函数
}).catch(function (err) {
// 失败的函数
})
1.3 Promise对象的状态
Promise 对象通过自身的状态,来控制异步操作。
Promise 实例具有三种状态。
- 异步操作未完成(pending)
- 异步操作成功(fulfilled)
- 异步操作失败(rejected)
这三种的状态的变化途径只有两种。
- 从“未完成”到“成功”
- 从“未完成”到“失败”
一旦状态发生变化,就凝固了,不会再有新的状态变化。这也是Promise这个名字的由来,它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。这也意味着,Promise实例的状态变化只可能发生一次。
因此,Promise的最终结果只有两种。
- 异步操作成功,Promise实例传回一个值(value),状态变为fulfilled。
- 异步操作失败,Promise实例抛出一个错误(error),状态变为rejected。
1.4 Promise.all
Promise.all()
方法用于将多个Promise实例,包装成一个新的Promise实例。
const p = Promise.all([p1, p2, p3]);
p的状态由p1,p2,p3 决定,分成两种情况。
- 只有
p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。 - 只要
p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
1.5 Promise.race
Promise.race()
方法同样是将多个Promise实例,包装成一个新的Promise实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p
的回调函数。
2 Generator函数
Generator函数是ES6提供的一种异步编程解决方案。
Generator函数是一个状态机,封装了多个内部状态。
执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。
2.1 基本语法
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 "aaa"//产出
console.log("gen内部",res1)
let res2 = yield "bbb"
console.log("gen内部",res2)
}
let g = gen()
let res1 = g.next("传入-11111") // 第1次next(),到yield停,"aaa"赋值给res1
console.log(res1) // 打印:aaa
let res2 = g.next("传入-22222") // 第2次next(),将"传入-22222"赋值给let res1 = yield "aaa"中的res1,打印:gen内部,传入-22222,到yield停,"bbb"赋值给res2
console.log(res2) // 打印:bbb
let res3 = g.next("传入-33333") // 将"传入-33333"赋值给let res2 = yield "bbb"中的res2,打印:gen内部,传入-33333
console.log(res3) // 打印:undefined
2.2 异步流程
2.2.1 手动版本
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)
})
})
//async await 内置自动执行器
2.2.2 自动版本
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); // 第1次next()
if(res.done) return
res.value.then(function (data) {
next(data); // 第2次next()
});
}
next();
}
AutoRun(gen);