CSDN话题挑战赛第2期
参赛话题:学习笔记
目录
生成器其实就是一个特殊的函数,其作用主要体现在异步编程。在此之前,我们实现异步编程采用的是纯回调函数(一层套一层 回调地狱)。
首先我们来认识一下生成器函数:
生成器函数与普通函数有所不同,它需要在 函数名与function 之间添加个 * 号。如:
- function * gen(){
- console.log("Hello");
- }
-
- let iterator = gen();
- console.log(iterator);
'运行

所以让gen()里面的代码运行只需运行iterator.next()

作用:切割符,把函数分为几段
- 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语句的返回结果。