generator函数

一、状态机

function * stateFn(){
    yield 'state1'
    var st2 = yield 'state2'
    yield step(st2)
}

二、自定义遍历器生成函数

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

三、返回遍历器对象

为普通对象加同步遍历器接口,就可以用for of遍历对象了,可以用for of,yield*,Array.from,扩展操作符,解构赋值等方法遍历同步的iterator接口。

1、将无参的Generator函数加到对象的Symbol.iterator属性上,遍历对象

function* objectEntries() {
  let propKeys = Object.keys(this);

  for (let propKey of propKeys) {
    yield [propKey, this[propKey]];
  }
}

const myObj = { name: 'Camille', age: 26 };

myObj[Symbol.iterator] = objectEntries;

for (let [key, value] of myObj) {
  console.log(`${key}: ${value}`);
}
//不用generator函数,也可以用for of 直接遍历Object.keys(myObj)
const myObj = { name: 'Camille', age: 26 };
for (var key of Object.keys(myObj)) {
  console.log(key + ": " + myObj[key]);
}

//或者遍历Object.entries(myObj)
const myObj = { name: 'Camille', age: 26 };
for (var [key,value] of Object.entries(myObj)) {
  console.log(key + ": " + value);
}

2、直接遍历以对象为参数的Generator函数

function* objectEntries(obj) {
  let propKeys = Reflect.ownKeys(obj);

  for (let propKey of propKeys) {
    yield [propKey, obj[propKey]];
  }
}

const myObj = { name: 'Camille', age: 26 };

for (let [key, value] of objectEntries(myObj)) {
  console.log(`${key}: ${value}`);
}
//不用generator函数,也可以用for of 直接遍历Reflect.ownKeys(myObj)
const myObj = { name: 'Camille', age: 26 };
for (var key of Reflect.ownKeys(myObj)) {
  console.log(`${key}: ${myObj[key]}`);
}

四、惰性求值
next()方法的参数是上一个yield表达式的返回值,yield表达式暂停执行,next()恢复执行。

五、错误处理机制

function * errFn(){
    try {
        yield 'es6 generator';
        yield 'vue';
    } catch(e) {
        console.log('内部捕获错误',e);
    }
    yield console.log('继续执行');
    yield console.log('不受影响');
}
var f = errFn();
f.next();
f.throw(new Error('外部抛出错误')); 
function * errFn(){
    try {
        yield 'es6 generator';
        throw new Error('内部抛出错误'); //全局throw命令
        yield 'vue';
    } catch(e) {
        console.log('内部捕获错误',e);
    }
}
var f = errFn();
try {
    console.log('第一次运行next方法', f.next());
    console.log('第二次运行next方法', f.next());
    throw new Error('外部捕获错误'); //全局throw命令
    console.log('第三次运行next方法', f.next());
} catch(e) {
    console.log('外部',e)
}

1、throw()和throw语句的区别
throw()是generator函数的一个方法,throw()方法抛出的错误既可以被generator函数内部的catch语句捕获,也可以被generator函数外部的catch语句捕获。
throw语句用于创建自定义错误,它和generator函数没有任何关系,可以独立存在。既可以出现在generator函数内部的try语句中,也可以出现在generator函数外部的try语句中。外部的throw语句只能被generator函数外部的catch语句捕获,不能被generator函数内部的catch语句捕获。
2、generator函数内部的catch语句和外部的catch语句
generator函数内部的catch语句可以捕获generator函数内部的throw语句,也可以捕获外部的throw()方法。
generator函数内部的catch语句如果捕获到异常,将不影响下次遍历,还会附带执行一次next()方法。generator函数外部的catch语句一旦捕获到异常,就会中断执行try里面剩余的语句了。
3、什么情况下中断?
generator函数外部的catch语句一旦捕获到异常,就会中断执行try里面剩余的语句了。
调用了throw()方法,却没写任何catch语句,程序会中断执行。

六、generator函数的this

function* gen() {
  this.a = 1;
  yield this.b = 2;
  yield this.c = 3;
}

function F() {
  return gen.call(gen.prototype);
}

var f = new F();

f.next();  // Object {value: 2, done: false}
f.next();  // Object {value: 3, done: false}
f.next();  // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3

 

转载于:https://www.cnblogs.com/camille666/p/es_generator.html

### 什么是 Generator 函数 Generator 函数是 ES6 中引入的一种特殊类型的函数,它可以返回一个迭代器对象。通过该迭代器对象,可以逐步执行 Generator 函数中的代码并获取其内部的值[^4]。 #### 基本语法 定义一个 Generator 函数时,在 `function` 关键字后面加上星号 (`*`) 表示这是一个 Generator 函数。在函数体中使用 `yield` 关键字暂停和恢复函数的执行,并返回相应的值[^3]。 ```javascript function* myGenerator() { yield 1; yield 2; yield 3; } const generator = myGenerator(); console.log(generator.next().value); // 输出 1 console.log(generator.next().value); // 输出 2 console.log(generator.next().value); // 输出 3 ``` 上述代码展示了如何创建一个简单的 Generator 函数以及如何通过 `.next()` 方法逐步获取生成器返回的值。 --- ### Generator 的工作原理 当调用一个 Generator 函数时,实际上并不会立即执行其中的代码,而是返回一个迭代器对象。每次调用迭代器的 `.next()` 方法时,都会从上一次停止的地方继续执行直到遇到下一个 `yield` 或者到达函数结束位置。 如果 Generator 函数中有多个 `yield` 表达式,则可以通过多次调用 `.next()` 来逐一处理这些表达式的值。 --- ### 复杂场景下的 Generator 使用 #### 调用嵌套的 Generator 函数 默认情况下,直接在一个 Generator 函数中调用另一个 Generator 函数不会自动展开后者的结果。为了实现这一点,需要显式地使用 `yield*` 将子生成器的内容合并到父生成器中[^5]。 ```javascript function* foo() { yield 'aaa'; yield 'bbb'; } function* bar() { yield* foo(); // 展开foo生成器的内容 yield 'ccc'; yield 'ddd'; } let iterator = bar(); for (let value of iterator) { console.log(value); } // aaa bbb ccc ddd ``` 在这里可以看到,`yield*` 提供了一种简洁的方式来组合不同层次的生成逻辑。 --- ### 实现异步操作的同步化表达 利用 Generator 函数配合协程模式(coroutine),能够简化复杂的异步流程管理问题。通常结合第三方库如 co.js 或原生的 async/await 功能来完成这一目标[^1]。 下面是一个基于手动驱动的方式模拟异步请求的例子: ```javascript function wait(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function* taskScheduler() { console.log('Task started'); yield wait(1000); // 模拟耗时任务 console.log('After first delay'); yield wait(2000); // 又一段延迟 console.log('All tasks completed'); } const schedulerIterator = taskScheduler(); (function exec() { const result = schedulerIterator.next(); if (!result.done) { result.value.then(() => exec()); } })(); ``` 此例子说明了即使面对多阶段延时计算的情况,借助于 Generators 和 Promises 结合也可以让程序看起来像顺序执行那样直观易懂[^1]。 --- ### 总结 - **基本功能**:提供一种机制允许开发者分段运行 JavaScript 程序片段。 - **核心概念**:依靠 `yield/yield*` 控制权转移;依赖 `.next()` 推动进程向前发展。 - **实际用途**:除了作为普通的迭代工具外,还特别适合用来解决复杂状态转换或者协调长时间等待的任务链路等问题。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值