(七) ES6 新特性 —— 生成器

CSDN话题挑战赛第2期
参赛话题:学习笔记

目录

生成器函数的声明与调用

生成器里面的yield函数

生成器函数参数

生成器函数实例——异步编程


生成器其实就是一个特殊的函数,其作用主要体现在异步编程。在此之前,我们实现异步编程采用的是纯回调函数(一层套一层 回调地狱)。

首先我们来认识一下生成器函数:

生成器函数的声明与调用

生成器函数与普通函数有所不同,它需要在 函数名与function 之间添加个 * 号。如:

function * gen(){
    console.log("Hello");
}

let iterator = gen();
console.log(iterator);

  1. console.log("Hello"); 这行的输出没有出现
  2. 返回的结果是一个迭代器对象

所以让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语句的返回结果。

猜你喜欢

转载自blog.csdn.net/a45667/article/details/127116633