ES6--生成器

62 阅读2分钟

Generator 生成器函数

生成器函数的声明和调用

生成器函数是 ES6 提供的一种 异步编程解决方案,语法行为与传统函数完全不同。

  • * 的位置没有限制
  • 使用 function * gen() 和 yield 可以声明一个生成器函数。生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值。
  • 每一个 yield 相当于函数的暂停标记,也可以认为是一个分隔符,每调用一次 next(),生成器函数就往下执行一段。
  • next 方法可以传递实参,作为 yield 语句的返回值

例如以下生成器函数中,3 个 yield 语句将函数内部分成了 4 段。

function* generator() {
    console.log('before 111'); // 生成器第 1yield 111;
    console.log('before 222'); // 生成器第 1yield 222;
    console.log('before 333'); // 生成器第 1yield 333;
    console.log('after 333'); // 生成器第 1 段
}
let iter = generator();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
/*
before 111
{ value: 111, done: false }
before 222
{ value: 222, done: false }
before 333
{ value: 333, done: false }
after 333
{ value: undefined, done: true }
*/Copy to clipboardErrorCopied

12.2 生成器函数的参数传递

function* generator(arg) {
    console.log(arg); // 生成器第 1 段
    let one = yield 111;
    console.log(one); // 生成器第 2 段
    let two = yield 222;
    console.log(two); // 生成器第 3 段
    let three = yield 333; 
    console.log(three); // 生成器第 4 段
}

let iter = generator('aaa'); // 传给生成器第 1 段
console.log(iter.next());
console.log(iter.next('bbb')); // 传给生成器第 2 段,作为这一段开始的 yield 语句返回值
console.log(iter.next('ccc')); // 传给生成器第 3 段,作为这一段开始的 yield 语句返回值
console.log(iter.next('ddd')); // 传给生成器第 4 段,作为这一段开始的 yield 语句返回值
/*
aaa
{ value: 111, done: false }
bbb
{ value: 222, done: false }
ccc
{ value: 333, done: false }
ddd
{ value: undefined, done: true }
*/Copy to clipboardErrorCopied

12.3 生成器函数案例

案例1:1s后输出111,2s后输出222,3s后输出333

  • 传统方式:嵌套太多,代码复杂,产生 回调地狱

    setTimeout(() => {
        console.log(111);
        setTimeout(() => {
            console.log(222);
            setTimeout(() => {
                console.log(333);
            }, 3000);
        }, 2000);
    }, 1000);Copy to clipboardErrorCopied
    
  • 生成器实现:结构简洁明了

    function one() {
        setTimeout(() => {
            console.log(111);
            iter.next();
        }, 1000);
    }
    
    function two() {
        setTimeout(() => {
            console.log(222);
            iter.next();
        }, 2000);
    }
    
    function three() {
        setTimeout(() => {
            console.log(333);
        }, 3000);
    }
    
    function* generator() {
        yield one();
        yield two();
        yield three();
    }
    
    let iter = generator();
    iter.next();Copy to clipboardErrorCopied
    

案例2:生成器函数模拟每隔1s获取商品数据

function getUsers() {
    setTimeout(() => {
        let data = '用户数据';
        iter.next(data); // 传参给生成器函数的第 2 段,后面类似
    }, 1000);
}

function getOrders() {
    setTimeout(() => {
        let data = '订单数据';
        iter.next(data);
    }, 1000);
}

function getGoods() {
    setTimeout(() => {
        let data = '商品数据';
        iter.next(data);
    }, 1000);
}

function* generator() {
    let users = yield getUsers();
    console.log(users);
    let orders = yield getOrders();
    console.log(orders);
    let goods = yield getGoods();
    console.log(goods);
}

let iter = generator();
iter.next();