ES6 |Generator

93 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

ES系列文章

Generator函数

ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。

Generator函数组成:

  • 一是在 function 后面,函数名之前有个 * ;
  • 函数体内部使用yield语句,定义不同的内部状态(yield在英语里的意思就是“产出”)。
//普通函数
function foo() {
    for (let i = 0; i < 3; i++) {
        console.log(i)
    }
}
foo()
//Generator函数
function* foo() {
    for (let i = 0; i < 3; i++) {
        yield i
    }
}
// console.log(foo())
let f = foo()
console.log(f.next())
console.log(f.next())
console.log(f.next())
console.log(f.next())

执行机制

调用 Generator 函数和调用普通函数一样,在函数名后面加上()即可,但是 Generator 函数不会像普通函数一样立即执行,而是返回一个指向内部状态对象的指针,所以要调用遍历器对象Iterator 的 next 方法,指针就会从函数头部或者上一次停下来的地方开始执行。

Generator函数不能作为构造函数使用,只能返回Generator生成器对象。

function* gen(args) {
    args.forEach(item => {
        yield item + 1
    })
}

yield关键字只能在生成器内部使用,不能在其他地方使用

function* gen(x) {
    let y = 2 * (yield(x + 1))
    let z = yield(y / 3)
    return x + y + z
}
let g = gen(5)
console.log(g.next()) // 6
console.log(g.next()) // NaN
console.log(g.next()) // NaN

let g = gen(5)
console.log(g.next()) // 6
console.log(g.next(12)) // y=24  8
console.log(g.next(13)) // z=13 x=5 42

yield句本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。

function* count(x = 1) {
    while (true) {
        if (x % 7 === 0) {
            yield x
        }
        x++
    }
}
let n = count()
console.log(n.next().value)
console.log(n.next().value)
console.log(n.next().value)
console.log(n.next().value)
console.log(n.next().value)

应用场景

function ajax(url, callback) {
    // 1、创建XMLHttpRequest对象
    var xmlhttp
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest()
    } else { // 兼容早期浏览器
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
    }
    // 2、发送请求
    xmlhttp.open('GET', url, true)
    xmlhttp.send()
    // 3、服务端响应
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
            var obj = JSON.parse(xmlhttp.responseText)
            // console.log(obj)
            callback(obj)
        }
    }
}

function request(url) {
    ajax(url, res => {
        getData.next(res)
    })
}

function* gen() {
    let res1 = yield request('static/a.json')
    console.log(res1)
    let res2 = yield request('static/b.json')
    console.log(res2)
    let res3 = yield request('static/c.json')
    console.log(res3)
}
let getData = gen()
getData.next()

一个前端小白,若文章有错误内容,欢迎大佬指点讨论!