「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。
一、generator
1.1 generator函数和普通函数的对比
下面是一段普通函数代码,我们可以发现,只要满足条件,函数就会一直执行。不会中间间断。
function foo() {
for(let i = 0;i < 3; i++) {
console.log(i)
}
}
foo()
下面得代码就是一段generator函数,我们可以看到function后面有*,而且会有一个yield关键字。
function* fun() {
for(let i = 0;i < 3; i++) {
console.log(i)
yield i
}
}
console.log(fun())
我们可以执行下面得代码,会发现代码并未执行。这是因为generator需要我们手动调用执行。手动调用next执行一次,这就说明generator是可以中断执行的。每调用一次,代码执行一次。返回值是一个generator对象,包含一个value和一个done,value就是yield的值,done代表这个函数是否执行完成。
function* fun() {
for(let i = 0;i < 3; i++) {
console.log(i)
yield i
}
}
let gen = fun()
console.log(gen.next()) //{value: 0, done: false}
console.log(gen.next()) //{value: 1, done: false}
console.log(gen.next()) //{value: 2, done: false}
console.log(gen.next()) //{value: undefined, done: true}
由于generator返回值是一个generator对象,所以并不能作为构造函数使用
1.2 yield关键字只能在generator函数中使用
yield关键字只能在generator函数中使用,是直接父子关系。下面得代码就会报错,因为yield出现在了一个箭头函数中,与gennerator函数不是吧直接的父子关系。
function* gen(arg) {
arg.forEach(element => {
yield element+1
})
}
1.3 next()参数是上一次yield的返回值
大多数人看下面的代码执行结构肯定是一头雾水,其实我们只需要弄清楚一点,next的参数是一次yield的返回值就可以了,第一次调用传入的是5而且generator函数又是手动执行的(中断执行的),所有返回值低第一个yield后面的计算结果,也就是5+2,结果是7。后面的结果是NaN,是因为第二次第三次next()时并没有传递参数,这就导致yield(x+2)的返回值是undefined,在进行后面的计算就是NaN了。
function* gen(x) {
let y = 2*(yield(x+2))
let z = yield (y/2)
return x + y + z
}
let g = gen(5)
console.log(g.next()) //{value: 7, done: false}
console.log(g.next()) //{value: NaN, done: false}
console.log(g.next()) //{value: NaN, done: true}
所以,我们每次调用时,都应该给next()传递一个参数,代码如下: 我们需要好好理解一下是如何计算的。相信搞懂generator这些特殊的地方,下面得结果肯定轻松稿定。
function* gen(x) {
let y = 2*(yield(x+2))
let z = yield (y/2)
return x + y + z
}
let g = gen(5)
console.log(g.next()) //{value: 7, done: false}
console.log(g.next(12)) //{value: 12, done: false}
console.log(g.next(19)) //{value: 48, done: true}
1.4 用generator控制死循环输出
generator可以有效的控制死循环输出,让死循环不在报错。
function* fun(x=1) {
while(true) {
if(x%7 === 0) {
yield x
}
x++
}
}
let res = fun()
console.log(res.next().value) //7
console.log(res.next().value) //14
console.log(res.next().value) //21
console.log(res.next().value) //28
1.5 generator对异步状态进行管理
我们还是以想连续三次请求三个接口为例,使用generator对异步状态进行管理,代码如下:
function ajax(url,callback) {
var xmlHttp
// 创建XMLHttpRequest
if(window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest()
}else { //兼容IE7之前的浏览器
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP')
}
//发送请求
xmlHttp.open('GET',url,true)
xmlHttp.send()
// 响应数据
xmlHttp.onreadystatechange = function() {
if(xmlHttp.readyState === 4 && xmlHttp.status === 200){
var res = JSON.parse(xmlHttp.responseText)
callback(res)
}
}
}
function getData() {
ajax(url, res => {
g.next(res)
})
}
function* gen() {
let r1 = yield getData('/api1')
let r2 = yield getData('/api2')
let r3 = yield getData('/api3')
}
let g = gen()
g.next()