Generator 基本用法
- 在普通函数前面加上 * ,表示Generator函数
- 在函数内,使用 yield关键词 暂停函数执行。可以向外抛出相关值,也可以接受函数外的值
- 在函数外,使用 next()方法 启动Generator函数。遇到 yield关键词 时,可获取其值。也可以传递参数到函数内
- 函数外可以抛出异常入函数内,函数内可使用 try…catch 捕获
console.log(`------------------------------\n----Generator基本用法\n------------------------------`)
// * 表示Generator函数
function* gener() {
try {
console.log("cernerator function")
//遇到 yield关键词,函数执行暂停。有返回值,则向外抛出含有返回值的对象
//同时,可以接受函数外的传值
let outerData = yield "inner data"
console.log(outerData) //outer data
} catch (error) {
console.log(error)
}
}
//调用Generator函数,只是返回Generator对象,并不是执行其代码
let generator = gener()
console.log(generator) // gener {<suspended>}
//调用next()方法,才是启动执行Generator函数的内部代码
//可以接受Generator函数内部的返回值
//返回对象中的 done 是指函数是否执行完成
let innerData = generator.next()
console.log(innerData) //{value: "inner data", done: false}
//再次启动Generator函数,可以传递值
generator.next("outer data")
//手动抛个异常
generator.throw(new Error("outer error"))
Generator 与 Promise结合调用
* 可以依次调用多个接口
* 将Promise的异步操作,通过Generator组装为近似同步的操作
(users.json)
[
{
"name": "asd",
"age": 32
},
{
"name": "bbb",
"age": 12
}
]
(classes.json)
[
{
"className": "A1班",
"level": "三年级"
},
{
"className": "A5班",
"level": "二年级"
}
]
(js)
console.log(`------------------------------\n----Generator 与 Promise结合调用\n------------------------------`)
//请求函数
const ajax = function (url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.responseType = "json"
xhr.onload = function () {
if (this.status == 200) {
resolve(this.response)
} else {
reject(this.statusText)
}
}
xhr.send();
})
}
//Generator函数
function* main() {
//请求classes.json数据,并返回包含Promise的对象,且暂停函数
let className = yield ajax("/api/classes.json")
console.log("className:", className) //className: A1班
//请求users.json数据,并返回包含Promise的对象,且暂停函数
let userName = yield ajax("/api/users.json")
console.log("userName:", userName)
}
//调用Generator函数,并启用Generator函数
let generator = main()
let classGenerator = generator.next()
console.log("classGenerator:", classGenerator) //classGenerator: {value: Promise, done: false}
//检查Generator函数是否完成
if (classGenerator.done) return
let classPromise = classGenerator.value//获取Promise对象
//获取ajax请求到数据
classPromise.then(res => {
let className = res[0].className
//拿到数据后,再次启动Generator函数,并将所需参数传递到Generator函数内容
//获取到下一个yield所在的ajax调用,并返回包含该调用的Promise的Generator对象
let userGenerator = generator.next(className)
console.log("userGenerator:", userGenerator) //userGenerator: {value: Promise, done: false}
//检查Generator函数是否完成
if (classGenerator.done) return
let userPromise = userGenerator.value
userPromise.then(userRes => {
let userName = userRes[0].name
console.log(userName)
//如果还有其他的调用,则继续...
})
})
Generator的执行器
- 利用递归的方法,简化上面的代码
(users.json)
[
{
"name": "asd",
"age": 32
},
{
"name": "bbb",
"age": 12
}
]
(classes.json)
[
{
"className": "A1班",
"level": "三年级"
},
{
"className": "A5班",
"level": "二年级"
}
]
(js)
console.log(`------------------------------\n----Generator的执行器\n------------------------------`)
//请求函数
const ajax = function (url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.responseType = "json"
xhr.onload = function () {
if (this.status == 200) {
resolve(this.response)
} else {
reject(this.statusText)
}
}
xhr.send();
})
}
//需调用接口的函数
function* generatorFn() {
try {
console.log("generator")
let users = yield ajax("/api/users.json")
console.log("generator users:", users) //generator users: (2) [{…}, {…}]
let classes = yield ajax("/api/classes.json")
console.log("generator classes:", classes) //generator classes: (2) [{…}, {…}]
//异常处
let errorTest = yield ajax("/api/error-path.json")
console.log("generator errorTest:", errorTest)
} catch (error) {
console.log(error)
}
}
//Generator的执行器
function co(generatorFn) {
const generator = generatorFn()
//递归方法
function handleResult(result) {
if (result.done) return//Generator函数执行结束,则停止递归
result.value.then(res => {
//启动Generator函数,并递归
handleResult(generator.next(res))
})
.catch(err => {//使用catch捕获异常
generator.throw(err)
})
}
//使用Generator函数,只需启用一次
handleResult(generator.next())
}
//使用执行器
co(generatorFn)
async 和 await 语法糖
- 与 * 和 yield 的使用差不多
- 不需要执行器,直接调用即可
- await只会出现在async修饰的函数内部
(简化上述代码)
console.log(`------------------------------\n----async和await语法糖\n------------------------------`)
//请求函数
const ajax = function (url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.responseType = "json"
xhr.onload = function () {
if (this.status == 200) {
resolve(this.response)
} else {
reject(this.statusText)
}
}
xhr.send();
})
}
//需调用接口的函数
//将 * 换成 async
//将 yield 换成 await
async function generatorFn() {
console.log("generator")
let users = await ajax("/api/users.json")
console.log("generator users:", users) //generator users: (2) [{…}, {…}]
let classes = await ajax("/api/classes.json")
console.log("generator classes:", classes) //generator classes: (2) [{…}, {…}]
//异常处
let errorTest = await ajax("/api/error-path.json")
console.log("generator errorTest:", errorTest)
}
//直接调用Generator函数即可
//不需要执行器,因为它是语言层面的,标准异步编程语法
//返回一个Promise的对象
generatorFn().then(res => {
console.log("all complete!")
}).catch(err => {
console.log(err)
})