CSDN话题挑战赛第2期
参赛话题:学习笔记
目录
生成器其实就是一个特殊的函数,其作用主要体现在异步编程。在此之前,我们实现异步编程采用的是纯回调函数(一层套一层 回调地狱)。
首先我们来认识一下生成器函数:
生成器函数的声明与调用
生成器函数与普通函数有所不同,它需要在 函数名与function 之间添加个 * 号。如:
function * gen(){
console.log("Hello");
}
let iterator = gen();
console.log(iterator);
- console.log("Hello"); 这行的输出没有出现
- 返回的结果是一个迭代器对象
所以让gen()里面的代码运行只需运行iterator.next()
生成器里面的yield函数
作用:切割符,把函数分为几段
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾部';
yield '真奇怪';
}
代码1-3是一段,3-5是一段,5-7是一段,7-9是一段。三个切割符产生四段代码。
function* gen() {
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有尾部';
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
iterator.next();
iterator.next();
iterator.next();
iterator.next();
每调用一次next()就执行一段。
我们可以将iterator.next()( ——>注意iterator.next()返回的是一个对象)的内容打印一下:
第一次调用返回第一个yield里面的内容,第二次调用返回第二个yield里面的内容,第三次调用返回第三个yield里面的内容,第一次接着往下走就没有了。
生成器函数参数
传参:
function* gen(arg) {
yield 111;
yield 222;
yield 333;
}
//执行获取迭代器对象
let iterator = gen('AAA');
我们试着打印以下arg:
function* gen(arg) {
console.log(arg);
yield 111;
yield 222;
yield 333;
}
//执行获取迭代器对象
let iterator = gen('AAA');
发现控制台并没有输出结果。
我们接着调用一下iterator.next()
function* gen(arg) {
console.log(arg);
yield 111;
yield 222;
yield 333;
}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
正常输出AAA 说明参数的传递并没有问题。
注意:next方法可以传入实参,传入的实参就是yield语句的返回结果。
function* gen(arg) {
console.log(arg);
let one = yield 111;
console.log(one);
yield 222;
yield 333;
}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
// //next方法可以传入实参
console.log(iterator.next('BBB')); //第二次调用的next的参数
// 将作为第一个yield语句的返回结果
继续往下:
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());
// //next方法可以传入实参
console.log(iterator.next('BBB')); //第二次调用的next的参数,将作为第一个yield语句的返回结果
console.log(iterator.next('CCC')); //第三次调用的next的参数,将作为第二个yield语句的返回结果
console.log(iterator.next('DDD')); //第四次调用的next的参数,将作为第三个yield语句的返回结果
生成器函数实例——异步编程
异步编程是一种事件驱动编程,请求调用函数或方法后,无需立即等待反应,可以立即执行其他任务,之前的任务响应返回后可以通过状态,通知和回调来通知调用者。
实例:文件操作 网络操作(ajax, request) 数据库操作
简单介绍一下异步编程之后,我们来看一下这样的一个需求:
1s 后控制台输出 111 2s后输出 222 3s后输出 333
简单实现的话我们可以通过定时器采取一层一层嵌套的方式来执行:
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 1000);
}, 2000);
}, 3000);
这样执行起来很简单,但是如果后面还有新的异步任务的话,还需要更多的去嵌套,代码缩进不断向前,阅读工作量巨大。
很容易造成回调地狱的现象。
所以新的异步解决方案就是我们可以通过生成器函数来完成:
三个函数分别完成三个异步任务。
function one() {
setTimeout(() => {
console.log(111);
iterator.next();//让下一段yield语句执行。
}, 1000);
}
function two() {
setTimeout(() => {
console.log(222);
iterator.next();
}, 2000);
}
function three() {
setTimeout(() => {
console.log(333);
iterator.next();
}, 3000);
}
// 把三个函数的调用放到了yield语句里面:
function* gen() {
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
// 让生成器函数调用起来。
iterator.next();
这样也可以实现我们的需求。
再一个需求:模拟获取,顺序获取数据 ——>用户数据 订单数据 商品数据
function getUsers(){
setTimeout(()=>{
let data = '用户数据';
//调用 next 方法, 并且将数据传入
iterator.next(data);//第二次调用next,将作为第一个yield语句的返回结果
}, 1000);
}
function getOrders(){
setTimeout(()=>{
let data = '订单数据';//第三次调用next,将作为第二个yield语句的返回结果
iterator.next(data);
}, 1000)
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据';
iterator.next(data);
}, 1000)
}
function * gen(){
let users = yield getUsers();
let orders = yield getOrders();
let goods = yield getGoods();
}
//调用生成器函数
let iterator = gen();
iterator.next();
当我们调用订单数据时,我们可能会需要用户数据的内容,所以可以再用户数据的函数中通过 iterator.next(data) 传递相关的内容,它将作为第一个yield语句的返回结果。