YBFACC / blog

仅记录个人学习使用
3 stars 0 forks source link

Generator #25

Open YBFACC opened 4 years ago

YBFACC commented 4 years ago

Generator

介绍

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

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

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

let a = [...fruit()]

generator大致的执行流程:

下面使用一个例子:

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 函数的语法