0
点赞
收藏
分享

微信扫一扫

Javascript(笔记37) - ES6特性 - 生成器

Javascript(笔记37) - ES6特性 - 生成器

生成器

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

生成器其实就是一个特殊的函数;

异步编程,纯回调函数,如: node fs  ajax mogodb

// 声明一个生成器函数
function* gen() { // 有个 * 很不一样;
console.log('hello generator');
}
let iterator = gen();
console.log(iterator); // gen {<suspended>}
iterator.next(); // hello generator

生成的时候不一样,执行的时候也不一样,生成器函数有个 next 方法,执行这个 next 才会有结果;

另外,在生成器函数,还可以出现  yield 语句

这个 yield 语句,可以理解为函数代码的分隔符,把函数的语句分割成几块;

function* gen() {
console.log('111');
yield '第一段分隔符';
console.log('222');
yield '第二段分隔符';
console.log('333');
yield '第三段分隔符';
console.log('444');
}
let iterator = gen();
iterator.next(); // 111
iterator.next(); // 222
iterator.next(); // 333
iterator.next(); // 444

这块代码被 yield 分隔符,分割成4段;每执行一次 next 方法,就执行一段语句直到第4次调用 next 方法,把执行完全部语句;

有 next 方法,就可以 for ... of 遍历,试一下:我们先把每一段执行的代码注释掉,看遍历结果:

function* gen() {
yield '第一段分隔符';
yield '第二段分隔符';
yield '第三段分隔符';
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

我们知道 next 方法返回的是一个对象,里面包括 value 和 done ;

Javascript(笔记37) - ES6特性 - 生成器_ES6

也就是说:

第一次调用 next 返回第一个 yield 的值和 done ;这个值目前是一个字符串;

第二次调用 next 返回第二个 yield 的值和 done;

以此类推,直到结束;


生成器参数传递

function* gen(arg){
console.log(arg);
let one = yield '111';
console.log(one);
let two = yield '222';
console.log(two);
let three = yield '333';
console.log(three);
}
let iterator = gen("AAA");
console.log(iterator.next()); // AAA 第一次,返回了实参 AAA;
console.log(iterator.next("BBB")); // BBB 第二次,返回了 one
console.log(iterator.next("CCC")); // CCC 第三次,返回了 two
console.log(iterator.next("DDD")); // DDD 第四次,返回了 three

有了这个特性支持,异步编程参数传递就可以实现了;

第一次调用 next(); 返回的是第一个 yield 以上的代码,即 实参传入的 “AAA”


生成器函数实例一

异步编程,如文件操作,网络操作(ajax,request),数据库操作

需求:1s 后控制台输出 111, 2s 后输出 222, 3s 后输出333;

定时器也是异步的;

setTimeout(()=>{
console.log(111); // 111
setTimeout(()=>{
console.log(222); // 222
setTimeout(()=>{
console.log(333); // 333
},3000);
},2000);
},1000);

这样也能实现需求,但是后面要跟新的异步的话,代码的缩进会不断推进,阅读和调试会很不方便;

这种现象叫:回调地狱

用生成器函数来实现需求:

function one(){
setTimeout(()=>{
console.log(111); // 111
iterator.next();
},1000);
}

function two(){
setTimeout(()=>{
console.log(222); // 222
iterator.next();
},2000);
}

function three(){
setTimeout(()=>{
console.log(333); // 333
iterator.next();
},3000);
}

function* gen(){
yield one();
yield two();
yield three();
}

let iterator = gen();
iterator.next();

通过初始的 iterator.next() 调用,执行 yield one() ; 再 next 以此类推,逐渐生成结果;

逻辑清晰完整,解决了回调地狱的问题;


生成器函数实例二

模拟获取: 用户数据,订单数据,商品数据

注意获取是有顺序的:即先有用户数据,才能有订单数据,才有商品数据;

function getUsers() {
setTimeout(() => {
let data = "用户数据";
// 调用 next ,并将数据传入
iterator.next(data);
}, 1000);
}

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

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

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

let iterator = gen();
iterator.next();

通过next 传参,最后集中输出数据;跟同步代码很像,实际是异步的,同时也解决了回调地狱问题;











举报

相关推荐

0 条评论