【手写 Promise 源码】第十五篇 - 了解 generator 生成器

328 阅读2分钟

一,前言

上一篇,实现了 promisify 和应用场景介绍,主要涉及以下几个点:

  • promisify 简介和测试;
  • promisify 功能的实现:promisify、promisifyAll;

目前,Promise 部分已基本完成,Promise 仅仅是对异步回到进行了优化,在 Promise 的内部依然还是回调,所以并没有解决“回调地狱”的问题;

最终解决方案还要使用 async/await,async/await 是基于 generator 的语法糖,而为了搞清楚 async/await 的原理,需要先对 generator、co 进行了解;

本篇,介绍 generator 生成器;


二,generator 简介

1,什么是 generator

  • Generator 函数是 ES6 提供的一种异步编程解决方案
  • Generator 函数,可以理解为一个状态机,内部封装多个状态,返回 Iterator 迭代器对象;

2,generator 的特征

  • 星函数:function 关键字与函数名之间有一个星号;
  • yield 表达式(意为“产出”):函数体内部使用 yield 语句,定义不同的内部状态;
  • 暂停执行功能:yield 表达式具有暂停执行的功能,通过 next 方法可以恢复执行;
  • next 方法:每调用一次 next 方法,就会从暂停处继续执行到下一个 yield 表达式为止;

因此,generator 可以把函数的执行权交给外部控制

3,generator 的使用

// 生成器函数: 返回 Iterator 迭代器
function * read(){ // 星函数
  console.log(1)
  yield 1;  // 代码执行遇到 yield 讲终止执行,外部调用 next 后继续
  console.log(2)
  yield 2; 
  console.log(3)
  yield 3; 
}

// 执行生成器函数,返回一个迭代器
let it = read();
it.next();// 走下一步逻辑   执行结果:1
it.next();// 走下一步逻辑   执行结果:2
it.next();// 走下一步逻辑   执行结果:3(此时虽然都走完了,但还需要在 next 一次才能知道)
it.next();// 已全部执行完成

4,generator 的功能分析

根据以上 generator 生成器函数的特性,即:代码的执行可以通过外部函数进行分步控制; 这是一个有限状态机:while(1){switch...case...}


三,generator 实现

1,generator 执行分析

babeljs: babel 能够将低级语法转换成为高级语法;

将之前示例进行转化:

image.png

右侧代码:

"use strict";

var _marked = /*#__PURE__*/regeneratorRuntime.mark(read);

function read() {
  return regeneratorRuntime.wrap(function read$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          console.log(1);
          _context.next = 3;
          return 1;

        case 3:
          console.log(2);
          _context.next = 6;
          return 2;

        case 6:
          console.log(3);
          _context.next = 9;
          return 3;

        case 9:
        case "end":
          return _context.stop();
      }
    }
  }, _marked);
}

var it = read();
it.next();
it.next();
it.next();
it.next();

代码分析:

  • while(1):表示有限状态机,内部的switch...case...会被执行多次;
  • _context.prev:是代码的执行指针,会根据指针逐层地向下依次执行;
  • 第一次_context.next = 0后,_context.prev被赋值为 0, 执行 case 0 的逻辑;执行完成后_context.next = 2,继续再执行执行 case 2 的逻辑...直至最后调用 _context.stop()完成;

四,结尾

本篇,主要介绍了 generator 生成器函数的使用和实现原理,主要涉及以下几个点:

  • generator 简介:特性、用法、功能分析;
  • generator 实现原理分析;

下篇,继续介绍 co 库:自动执行 Generator 生成器函数;