文章目錄
- Generator 基本用法
- Generator 與 Promise結合調用
- Generator的執行器
- async 和 await 文法糖
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)
})