异步三部曲之Generator

基本写法

function *gen1() {
  yield 1
}
console.log(gen1())   // gen1 {<suspended>}
//  等价于
function* gen2() {
  yield 1
}
console.log(gen2())   // gen2 {<suspended>}
//  等价于
function * gen3() {
  yield 1
}
console.log(gen3())   // gen3 {<suspended>}

const genObj = {
  *gen(){
    yield 1
  }
}
console.log(genObj.gen())   // gen {<suspended>}
//  等价于
const genObj1 = {
  gen: function *() {
    yield 1
  }
}
console.log(genObj1.gen())  // gen {<suspended>}

Generator函数的写法就是在关键字functionfunctionName之间加一个 * ,至于空格并未有严格要求,所以gen1gen2gen3都是可行的。

Generator执行方式

console.log('Hi')

function *gen() {
  console.log('Hello Generator')
  let a = yield 2;
  console.log(a)

  return a + 1;

  yield 3
  console.log('Bay Generator')
}

const g = gen()

console.log('Bay')

// Hi
// Bay

console.log(g.next())
// Hello Generator
// {value: 2, done: false}
console.log(g.next())
// undefined
// {value: NaN, done: true}
console.log(g.next())
// {value: undefined, done: true}
console.log(g.next())
// {value: undefined, done: true}

暴躁老哥:那yield是个啥玩意?
yield是一个标记,用来告诉Generator函数到这停一下,并且yield默认是不返回值的。
上面的例子可以看到Generator函数在执行之后只会返回一个指针对象,内部的代码并不会执行,当调用next时才开始执行,next执行后会把指针指向下一步,执行两个指针中间的部分。同时return也代表一个指针位置,并且还是具有停止效果。
next返回{ value: any, done: Bollean }done用来告诉我们遍历是否完成。value代表当前值。
暴躁老哥:能不能说点我听得懂的?
Generator函数就像公交车一样,执行之后得到路线,next方法告诉它:你该去下一站了,你不告诉它就不动,哎~就是玩。done就是表示有没有到终点,value表示到了哪一站。

Generator.prototype.next 方法

next 方法就是指针移到下一个yield,同时next可以传一个参数,用来指定上一个yield的返回值。

function *gen() {
  let a = yield 2;
  console.log(a)

  return a + 1;
}

const g = gen()

console.log(g.next())
// {value: 2, done: false}

console.log(g.next(3))
// 3
// {value: 4, done: true}

第一次调用next传入参数是无效的,因为它代表开始,前面并没有yield。上面例子可以看到,第一次调用next开始执行,遇到yield就停止了,同时把值传了出来,第二次调用时传入了3,所以a就变成了3,最后返回的就是4

Generator.prototype.throw 方法

throw方法的作用就是让Generator函数在这一步抛出一个错误,可在内部捕获,也可在外部捕获。

function *gen() {
  let a = 0
  try{
    yield a = 1
  } catch(err) {
    console.log('内部捕获', err)
  }
  console.log(a)
}

const g1 = gen()

console.log(g1.next())
// {value: 1, done: false}
console.log(g1.throw('来个红色'))
// 内部捕获 来个红色
// 1
// {value: undefined, done: true}

try{
  console.log(g1.throw('再来个红色'))
} catch(err) {
  console.log('外部捕获', err)
}
// 外部捕获 再来个红色

throw方法会在上一个指针处抛出一个错误,当内部没有进行捕获时,就会被外部捕获,如果外部也没有进行捕获,那么程序就会出错

Generator.prototype.return 方法

return方法会使Generator函数停止运行,并返回传入的值

function *gen() {
  console.log('go');
  yield 1
  console.log('第一站')
  yield 2
  console.log('第二站')
  yield 3
  console.log('第三站')
}

const g = gen();
g.next()  // {value: 1, done: false}
// go
g.next()  // {value: 2, done: false}
// 第一站
g.next()  // {value: 3, done: false}
// 第二站
g.next()  // {value: undefined, done: true}
// 第三站

const g1 = gen();
g1.next()  // {value: 1, done: false}
// go
g1.return('提前结束')  // {value: 提前结束, done: true}
g1.next()  // {value: undefined, done: true}
g1.next()  // {value: undefined, done: true}

自动执行

function *gen() {
  yield 1
  yield 2
  yield 3
  return 4
}

const g = gen();
let next = g.next()
console.log(next.value)
while(!next.done){
  next = g.next();
  console.log(next.value)
}
// 1
// 2
// 3
// 4

const g1 = gen()
console.log([...g1])
// [1, 2, 3]

for(let v of gen()){
  console.log(v)
}
// 1
// 2
// 3

当都是同步操作时可直接遍历指针对象,但是此操作会忽略 return。调用 next 方法可获取到 return 值。

yield* 语法

function *gen1() {
  yield 'a'
  yield 'b'
  return 'ab'
}

function *gen() {
  yield 1
  yield 2
  yield* gen1()
  yield 3
  return 4
}

const g = gen();
let next = g.next()
console.log(next.value)
while(!next.done){
  next = g.next();
  console.log(next.value)
}
// 1
// 2
// a
// b
// 3
// 4

yield*语法可以把别的Generator函数进行执行,yield会返回一个指针对象

简易异步自动执行

配合Promise实现处理异步并自动执行的一个简单案例

function thunk(fn, ...args) {
    const ctx = this;
    return function (callback) {
      try {
        const res = fn.apply(ctx, args)
        return res
      } catch (err) {
        callback(err);
      }
    }
}

function run(gen, ...arg) {
  const g = gen(...arg);
  function next(err, data) {
    err && (console.error(err))
    let result = g.next(data);
    if (result.done) return;
    const { value, done } = result;
    if(value.then) {
      value.then(res => {
        next(null, res)
      })
    }else if(typeof value === 'function') {
      Promise.resolve(value(conso.error)).then(res => {
        next(null, res)
      })
    }else {
      next(value)
    }
  }

next();
}

function test() {
  return new Promise((resolve, reject) => {
    resolve(1)
  }).then(res => {
    console.log(1)
    return res
  })
}

function *testSaga(time) {
  let resoult = {}
  yield new Promise(function(resolve, reject) {
    setTimeout(() => {
      resolve({
        saga: 2,
        list: ['hello']
      })
    }, time)
  }).then(res => {
    resoult = res
  })
  console.log('resoult', resoult)
  const b = yield thunk(test);
  console.log('b', b)
}

run(testSaga, 1000)

// resoult {saga: 2, list: Array(1)}
// 1
// b 1
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容