Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generator #25

Open
YBFACC opened this issue Jul 4, 2020 · 0 comments
Open

Generator #25

YBFACC opened this issue Jul 4, 2020 · 0 comments

Comments

@YBFACC
Copy link
Owner

YBFACC commented Jul 4, 2020

Generator

介绍

geneartor 函数的特征:function与函数名之间会有个*号,函数内部有 yield 表达式。

  • 执行 Generator 函数会返回一个迭代器。

    当然我们可以使用 for...of...或者扩展运算符进行操作。

function* fruit() {
  yield 'apple'
  yield 'pear'
  return 'ending'
}

for (const iterator of fruit()) {
  console.log(iterator) //apper pear
}

let a = [...fruit()]

generator大致的执行流程:

  • 执行Iteratornext()

    • 函数压入调用栈,代码从头或者上次中断的地方开始执行
    • 遇到 yield 关键字,返回一个对象{ value: value, done: false }
      • value:紧跟在 yield 关键字后的表达式计算值
      • donegenerator函数未执行完毕
    • 函数保留当前环境,挂起弹出调用栈
  • 执行return时,返回一个对象{ value: value, done: true }

    • valuereturn将要返回的值
    • donegenerator函数执行完毕

下面使用一个例子:

function* fruit() {
  yield 'apple'
  yield 'pear'
  return 'ending'
}

var _fruit = fruit()

_fruit.next()//{ value: 'apple', done: false }
_fruit.next()//{ value: 'pear', done: false }
_fruit.next()//{ value: 'ending', done: true }

yield

  1. yield关键字只能在 generator 函数中使用。不可以跨函数。
function* fruit() {
  let arr = ['apple', 'pear', 'ending']
  arr.forEach(item=>{
    yield item
  })
  return 
}

这样改变函数将会报错。

  1. yield是”懒执行“,只会在运行需要执行时才执行。
function* fruit() {
  yield 'pear'
  yield console.log('执行')
  return 'ending'
}

var _fruit = fruit()

_fruit.next()
_fruit.next()
_fruit.next()
  1. yield 放在包含在另一个表达式中需要()
function* fruit() {
  yield 1 + (yield 2)
}

var _fruit = fruit()

_fruit.next()
_fruit.next(2)
_fruit.next()

next

next可以启动或者继续执行generator 函数。

next可以携带返回值,作为上次执行 yield 的返回值。

function* fruit() {
  let a = yield 1
  let b = yield 2
  return a + b
}

var _fruit = fruit()

_fruit.next()
_fruit.next('a')
_fruit.next('b')

throw

throw用于在状态机内部抛出错误。这个是挂载在原型链上的throw方法与throw不同。当使用throw后进入执行状态,可以继续往下执行。

function* fruit() {
  try {
    let a = yield 1
    let b = yield 2
  } catch (error) {
    console.log('error=>' + error)
  } finally {
    return 'end'
  }
}

var _fruit = fruit()

_fruit.next() //{ value: 1, done: false }
_fruit.throw('a') //{ value: 'end', done: true }
_fruit.next('b') //{ value: undefined, done: true }

如果状态机函数内部没有try,则会在外部捕获。如果外部也没有try,则程序报错终止。

function* fruit() {
  let a = yield 1
  let b = yield 2
  let c = yield 3

  return 'end'
}

var _fruit = fruit()

try {
  _fruit.next()//Object {value: 1, done: false}
  _fruit.next('b')//Object {value: 2, done: false}
  _fruit.throw('a')
} catch (error) {
  console.log('error=>' + error)
}

在开始时就抛出错误,这时generator函数还未开始执行,直接在外部捕获。如果外部也没有try,则程序报错终止。

function* fruit() {
  try {
    let a = yield 1
    let b = yield 2
    let c = yield 3

    return 'end'
  } catch (error) {
    console.log('内部' + error)
  }
}

var _fruit = fruit()

try {
  console.log(_fruit.throw('a')) //外部a
  console.log(_fruit.next())
  console.log(_fruit.next('b'))
} catch (error) {
  console.log('外部' + error)
}

如果没有在内部进行捕获,就提前结束generator函数。

function* fruit() {
  let a = yield 1
  let b = yield 2
  let c = yield 3
  return 'end'
}

var _fruit = fruit()

try {
  console.log(_fruit.next()) //Object {value: 1, done: false}
  console.log(_fruit.throw('a'))
} catch (error) {
  console.log('外部' + error)
}
console.log(_fruit.next('b')) //Object {value: undefined, done: true}

return

在外部提前结束generator函数。

使用return函数返回一个对象。valuereturn中的参数,donetrue

function* fruit() {
  let a = yield 1
  let b = yield 2
  let c = yield 3
  return 'end'
}

var _fruit = fruit()

console.log(_fruit.next()) //{ value: 1, done: false }
console.log(_fruit.return('a')) //{ value: 'a', done: true }
console.log(_fruit.next('b')) //{ value: undefined, done: true }

会执行finally语句中的内容。

function* fruit() {
  try {
    let a = yield 1
    let b = yield 2
  } finally {
    let c = yield 3
  }
}

var _fruit = fruit()

_fruit.next() //{ value: 1, done: false }
_fruit.return('a') //{ value: 3, done: false }
_fruit.next('b') //{ value: 'a', done: true }
_fruit.next() //{ value: undefined, done: true }

如果finally中有return,忽略参数

function* fruit() {
  try {
    let a = yield 1
    let b = yield 2
  } finally {
    let c = yield 3
    return 'end'
  }
}

var _fruit = fruit()

_fruit.next() //{ value: 1, done: false }
_fruit.return('a') //{ value: 3, done: false }
_fruit.next('b') //{ value: 'end', done: true }
_fruit.next() //{ value: undefined, done: true }

参考

Generator 函数的语法

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant