浅谈ES6中的迭代器

103 阅读2分钟

生成器的背景

Promise的缺陷:还是有大量的回调函数,普通函数多一个*,直到调用next方法才执行,这使得异步调用逐渐扁平化。

生成器是一种返回迭代器的函数,通过function关键字之后的表示。函数中会用到新的关键字yield。星号可以紧挨着function 也可以中间加一个空格。

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

基本用法

生成器返回的是一个迭代器对象。可以用函数声明和函数表达式创建生成器。但是不能用箭头函数

function * a(){};
const b = function *(){};
console.log(a()) // Object [Generator] {};

yield后边返回的是next返回值的value

function * a() {
    yield 1;
    yield 2;
    yield 3;
}
const i = a();
console.log(i.next());
console.log(i.next());
console.log(i.next());
console.log(i.next());

// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: undefined, done: true }

生成器解决回调地狱

假设现在有这样一个场景,我们根据小明的身份证号获取小明的基础信息,根据小明的基础信息的地址查询小明的家乡景区,根据景区获取景区的详细介绍。最后用基础信息和家乡介绍生成小明的自我介绍。

ES5的写法

function getIntroduce(cardId) {
    setTimeout(() => { 
        const personInfo = {
            id: cardId,
            name: '小明',
            address: '北京',
            age:19
        }
        console.log(personInfo);
        setTimeout(() => { 
            const Attractions = ['故宫', '长城', '颐和园'];
            console.log(Attractions);
            setTimeout(() => { 
                const sebnceIntro = Attractions[0] + '是一个五A级景区,他的历史悠久,记载着很多。。。';
                console.log(sebnceIntro);
                const res = `我叫${ personInfo.name },今年${ personInfo.age }来自${ personInfo.address },我的家乡有谱很多名胜古迹,比如${ Attractions.join(',') }等等,其中${sebnceIntro}希望大家有机会常来玩`;
                console.log(res);
            }, 1000);
        }, 3000);
    }, 200);
};
getIntroduce(1)

生成器的写法:解决回调地狱

function getPersonInfo(id){ 
    setTimeout(() => { 
        const res = {
            id: id,
            name: '小明',
            address: '北京',
            age:19
        }
        // 异步拿到之前的数据之后 才让代码继续执行
        introduce.next(res);
    },200);
}
function getSenceListByName(id) { 
    setTimeout(() => { 
        const res = ['故宫','长城','颐和园'];
        introduce.next(res);
    },3000);
}
function getSenceInfoByName(name) { 
    setTimeout(() => { 
        const res = name + '是一个五A级景区,他的历史悠久,记载着很多。。。';
        introduce.next(res);
    },1000);
}

function * getIntroduce(cardId) {
    const personInfo = yield getPersonInfo(cardId);
    console.log(personInfo);
    const Attractions = yield getSenceListByName(personInfo.address);
    console.log(Attractions);
    const sebnceIntro = yield getSenceInfoByName(Attractions[0]);
    console.log(sebnceIntro);
    const res = `我叫${personInfo.name},今年${personInfo.age}来自${personInfo.address},我的家乡有谱很多名胜古迹,比如${ Attractions.join(',') }等等,其中${sebnceIntro}希望大家有机会常来玩`;
    console.log(res);

}
const introduce = getIntroduce(1);
introduce.next();
console.log();

高级生成器

给迭代器传参数,如果给next函数传参数,这个参数就会作为上一个yield语句的返回值。这个也是迭代器实现异步编程的关键特点。

function* a() {
    const res1 = yield 1;
    const res2 = yield 2;
    const res3 = yield 3;
    console.log(res1,res2,res3) // AAA BBB CCC
};
const i = a();
console.log(i.next());
console.log(i.next('AAA'));
console.log(i.next('BBB'));
console.log(i.next('CCC'));

抛出错误
允许通过throw给迭代器抛出错误。
返回语句
允许生成器用return语句结束函数,且设置最后一个next的value。
委托生成器
给yield加一个星号,可以将两个生成器合成一个生成器。

function* b() { 
    yield 'mm';
    yield 'bb';
};
function* a() {
    yield * b();
    yield 2;
    yield 3;
};
const i = a();
for (m of i) { 
    console.log(m);
}
// mm bb 2 3