我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文对nodejs的生成器做个简要的描述,它和python的生成器是存在差别的。所以,完全套用pythonyield用法的话,可能会产生误解。本文以苏南大叔对JavaScript里面的生成器的理解为主,如有偏差,欢迎留言。

苏南大叔:JavaScript生成器,如何定义一个生成器,如何使用yield? - js-yield-hero
JavaScript生成器,如何定义一个生成器,如何使用yield?(图2-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0chrome@131.0.6778.205yield语句就像是个指针,随着指针的移动,从一个yield走向另外一个yield,最终碰到return

定义生成器

JavaScript里面的Generator生成器,是很奇怪的。它是通过在函数定义的时候,加个*来表示一个生成器的。

  • 没有匿名函数版的生成器,匿名函数不能加*,必须有function关键字。
  • async*,还可以同时作用到一个function关键字上,左右护法。
  • *是靠近左边或者右边或者中间,不重要。但是,格式化函数的时候,就会变成function*
  • 生成器的重要标识就是function关键字后面的这个*,而不是yield
  • 能用yield就别用return来返回值,虽然两者的功能看起来一致。但是,有些写法里面只认yield,不认return
function* g0() {
  console.log("g0");
}
function * g1() {
  console.log("g1");
}
const g2 = function *() {
  console.log("g2");
};
const g3 = async function * () {
  console.log("g3");
};

仅定义不执行

在生成器名字后面加上一个(),并不会执行这个生成器函数。或者说,function*返回值就是函数本身,这也能解释它为啥不执行函数体内的逻辑这个问题。

let a = g0();
let b = g1();
let c = g2();
let d = g3();

上述代码执行完后,生成器内部的console.log()并没有被执行。它(们)等待着.next()命令。

a.next();
b.next();
c.next();
d.next();

.next()、yield、return

.next()使得生成器逻辑得到继续运行,但是碰到yield就会停止执行。当.next()再次执行的时候,从yield的下一个逻辑开始执行,直到碰到下一个yield逻辑(或者return)为止。【仔细品味这句话,一次一次的想】

yield的作用是:阻碍并返回一个值。

  • .next()yield拿到的返回值很奇怪,是个对象。类似:{ value: 1, done: false }
  • .next()可以无限执行,并不会爆异常,恒定会得到{ value: undefined, done: true }
function* g0() {
  let i = 0;
  yield i++;
  yield i++;
  return i;
}
let a = g0();
console.log(a.next());   // { value: 0, done: false }
console.log(a.next());   // { value: 1, done: false }
console.log(a.next());   // { value: 2, done: true }
console.log(a.next());   // { value: undefined, done: true }
console.log(a.next());   // { value: undefined, done: true }

所以,donetrue的条件是:确实执行到了末尾。比如:碰到了return,或者}

function* g0() {
  let i = 0;
  yield i++;
  yield i++;
}
let a = g0();
console.log(a.next());   // { value: 0, done: false }
console.log(a.next());   // { value: 1, done: false }
console.log(a.next());   // { value: undefined, done: true}
console.log(a.next());   // { value: undefined, done: true }

.next(外部值) <=> yield 内部值

执行一个生成器,就是外部和内部不断交互的结果。

  • 内部可以通过yield 内部值来使得外部的.next()获得“内部值”。
  • 通过.next(外部值)使得内部的yield左边的表达式获得“外部值”。【这个逻辑很惊为天人】

苏南大叔:JavaScript生成器,如何定义一个生成器,如何使用yield? - 运行结果
JavaScript生成器,如何定义一个生成器,如何使用yield?(图2-2)

function* g0() {
  let i = 0;
  let j = yield i++;
  yield j++;
  return j;
}
let a = g0();
console.log(a.next(55));   // { value: 0, done: false }
console.log(a.next(66));   // { value: 66, done: false }
console.log(a.next(77));   // { value: 67, done: true }
console.log(a.next(88));   // { value: undefined, done: true }
  • .next(55)的时候,代码从右往左执行到yieldy,就返回了i0
  • .next(66)的时候,代码从yieldy从右往左执行,66被带入,实际执行的是let j = 66

相关文章

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js