js异步编程之Generator

Generator介绍

Generator 的中文名称是生成器,它是ECMAScript6中提供的新特性。在过去,封装一段运算逻辑的单元是函数。函数只存在“没有被调用”或者“被调用”的情况,不存在一个函数被执行之后还能暂停的情况,而Generator的出现让这种情况成为可能。

通过function*来定义的函数称之为“生成器函数”(generator function),它的特点是可以中断函数的执行,每次执行yield语句之后,函数即暂停执行,直到调用返回的生成器对象的next()函数它才会继续执行。

也就是说Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数返回一个遍历器对象(一个指向内部状态的指针对象),调用遍历器对象的next方法,使得指针移向下一个状态。每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。

yield关键字

真正让Generator具有价值的是yield关键字,这个yield关键字让 Generator内部的逻辑能够切割成多个部分。

let compute = function* (a, b) {
  let sum = a + b;
  yield console.log(sum);
  let c = a - b;
  yield console.log(c);
  let d = a * b;
  yield console.log(d);
  let e = a / b;
  console.log(e);
};
// 执行一下这个函数得到 Generator 实例
let generator = compute(4, 2);
// 要使得函数中封装的代码逻辑得到执行,还得需要调用一次next方法。
generator.next();

----------
var compute = function* (a, b) {
  let sum = a + b;
  yield sum;
  let c = a - b;
  yield c;
  let d = a * b;
  yield d;
  let e = a / b;
  e;
};

输出结果:
6
{value: undefined, done: false}

发现函数执行到第一个yield关键字的时候就停止了。要让业务逻辑继续执行完,需要反复调用.next()

generator.next();
generator.next();
generator.next();
generator.next();

可以简单地理解为yield关键字将程序逻辑划分成几部分,每次.next()执行时执行一部分。这使得程序的执行单元再也不是函数,复杂的逻辑可以通过yield来暂停

  1. .next()调用时,返回一个对象

yield除了切割逻辑外,它与.next()的行为息息相关。每次.next()调用时,返回一个对象,这个对象具备两个属性。
其中一个属性是布尔型的done。它表示这个Generator对象的逻辑块是否执行完成。
另一个属性是value,它来自于yield语句后的表达式的结果。

function * getNumbers(num) {
    for(let i=0; i

输出结果:
{value: 0, done: false}
undefined
{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
{value: 4, done: false}
{value: 5, done: false}
{value: 6, done: false}
{value: 7, done: false}
{value: 8, done: false}
{value: 9, done: false}
{value: "ok", done: true}
done

  1. 可以通过向.next()传递参数
let compute = function* (a, b) {
  var foo = yield a + b;
  console.log(foo);
};

let generator = compute(4, 2);
generator.next(); // {value: 6, done: false}
generator.next("Hello world!"); //Hello world! {value: undefined, done: true}

通过.next()传递参数,可以赋值给yield关键字前面的变量声明。

所以,对于Generator而言,它不仅可以将逻辑的单元切分得更细外,还能在暂停和继续执行的间隔中,动态传入数据,使得代码逻辑可以更灵活。

使用 Generator 编写状态切换逻辑代码

function * loop(list, max=Infinity) {
    for(let i=0; i e.target.className = 'off',
//     e => e.target.className = 'on'
// ));

switcher.addEventListener('click', toggle(
    e => e.target.className = 'off',
    e => e.target.className = 'warn',
    e => e.target.className = 'on'
));

完整代码:https://code.h5jun.com/yeyo/edit?html,css,js,output

References

Generator与异步编程
基于 Generator 与 Promise 的异步编程解决方案

你可能感兴趣的:(js异步编程之Generator)