十二、生成器

郁子大约 3 分钟约 752 字笔记ECMAScript尚硅谷李强

(一)生成器简介

  • ES5 异步编程使用纯回调函数
    • node
    • fs
    • ajax
    • mongodb
    • 一层套一层,形成回调地狱
  • 生成器是一个函数,是 ES6 提供的一种异步编程解决方案
    • 语法行为与传统函数完全不同

1.声明生成器函数

  • * 位置可以不同
  • 直接调用生成器函数无法执行
    • 因为本质是一个迭代器对象
    • 需要执行 next() 函数才可以调用
// function * gen1(){}
// function* gen2(){}
// function *gen3(){}

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

let iterator = gen();
console.log(iterator);
// gen {<suspended>}
iterator.next();
// Hello generator.

2.yield 语句

  • 生成器函数内部可以出现 yield 语句
  • yield 是函数代码的分隔符
function* gen() {
  console.log(111);
  yield "一只没有耳朵";
  console.log(222);
  yield "一只没有尾巴";
  console.log(333);
  yield "真奇怪";
  console.log(444);
}

let iterator = gen();
console.log(iterator);
iterator.next();
// 111
iterator.next();
// 222
iterator.next();
// 333
iterator.next();
// 444

3.遍历

function* gen() {
  yield "一只没有耳朵";
  yield "一只没有尾巴";
  yield "真奇怪";
}

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

for (let v of gen()) {
  console.log(v);
}

(二)生成器函数参数

  • next() 方法可以传入实参
  • 第二次调用 next() 方法传入的参数将作为第一个 yield 语句的整体返回结果
  • 第三次调用 next() 方法传入的参数将作为第二个 yield 语句的整体返回结果
  • 第四次调用 next() 方法传入的参数将作为第三个 yield 语句的整体返回结果
function* gen(arg) {
  console.log(arg); //AAA

  // yield 111;
  let one = yield 111;
  console.log(one); //BBB

  // yield 222;
  let two = yield 222;
  console.log(two); //CCC

  // yield 333;
  let three = yield 333;
  console.log(three); //DDD
}

// 执行获取迭代器对象
let iterator = gen("AAA");
console.log(iterator.next());
// {value: 111, done: false}

console.log(iterator.next("BBB"));
// {value: 222, done: false}

console.log(iterator.next("CCC"));
// {value: 333, done: false}

console.log(iterator.next("DDD"));
// {value: undefined, done: true}

(三)案例实操

  • 异步编程
    • JS 本身是异步单线程编程的,很多操作都是异步实现
  • 如:文件 I/O 操作、网络操作(ajax、request)、数据库操作等

1.实现 1s 后控制台输出 111,2s 后输出 222,3s 后输出 333

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

// 生成器函数
function one() {
  setTimeout(() => {
    console.log(111);
    iterator.next();
    // 222
  }, 1000);
}

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

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

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

// 调用生成器函数
let iterator = gen();
iterator.next();
// 111

2.模拟获取以下数据:用户数据、订单数据、商品数据

  • 有用户数据才有订单数据,再有商品数据
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();

// 以下调用不符合实际场景,因为数据之间有依赖关系
// getUsers();
// getOrders();
// getGoods();
上次编辑于: