使用 Generator 处理异步调用

Generator 是 ES6 的新规范,它属于函数的一部分,常用于处理异步代码,本篇文章将向大家简单介绍一下 Generator ,如有错误,欢迎大家批评指正哈!

1.一个简单的Generator

这是一个简单的 Generator 例子:

function* gen() {
    return 'first generator';
}
let generatorResult = gen();

使用 * 表示这是一个Generator函数

我们在控制台打印一下 generatorResult ,结果是:

console.log(generatorResult)
	
  [object Generator]: {}
	__proto__: Object
  undefined

这说明 generatorResult 不是一个普通的函数,而是一个 Generator 原型的实例,我们需要调用该实例的next方法取值,next 返回的对象中包含了 value 属性

generatorResult.next()

  [object Object]: {done: true, value: "first generator"}

注意事项:

  • 不能无限制地调用 next 从 Generator 中取值,Generator 如同序列,一旦序列中的值被消费就不能再次消费它
  • 为了能够再次消费该序列,需要创建另一个 Generator 实例
generatorResult.next().value  // 第一次取值
  "first generator"  

generatorResult.next()
  [object Object]: {done: true, value: undefined}

generatorResult.next().value  //第二次取值
  undefined

2.yield关键字

在 Generator 函数中有一个新的关键字,称为 yield

一个简单的 Generator 序列:

function* genSequence() {
    yield 'first';
    yield 'second';
    yield 'third'
}
let generatorSequence = genSequence();

控制台输出:

generatorSequence.next()
  [object Object]: {done: false, value: "first"}

generatorSequence.next().value
  "second"

generatorSequence.next().value
  "third"

通过上面的操作我们可以总结出:

  • yield 使 Generator 函数暂停了执行并将结果返回给调用者
  • 调用一次后,yield 将函数置于暂停模式并返回值,而且还准确地记住了暂停的位置
  • 带有 yield 的 Generator 都会以惰性求值的顺序执行(当我们需要时,相应的值才会被返回)

3.done 属性

done属性清楚地告诉我们 Generator 序列的消费情况

generatorSequence.next()
[object Object]: {done: false, value: "first"}

generatorSequence.next().value
"second"

generatorSequence.next().value
"third"

generatorSequence.next().value
undefined

generatorSequence.next()
[object Object]: {done: true, value: undefined}
  • done 为true 表示 Generator 序列已经完全消费了
  • done 为false 表示还未消费完

4.向 Generator 传递数据

创建一个新的函数和 Generator 实例 :

function* sayName() {
    var firstName = yield;
    var secondName = yield;
    console.log(firstName + secondName)
}
let fullName = sayName();

然后我们在控制台输入:

fullName.next()
  [object Object]: {done: false, value: undefined}

fullName.next('chen')
  [object Object]: {done: false, value: undefined}

fullName.next('xiansheng')
  chenxiansheng
  [object Object]: {done: true, value: undefined}

是不是很神奇呢!下面说一下执行过程:

第一次调用 next 时,代码将返回并暂停于:

var firstName = yield;

由于没有通过 yield 发送任何值,next 将返回 undefined

第二次调用 next 时, Generator 将从上一次暂停的状态恢复,即这一行:

var firstName = yield;

由于本次调用 next 时传入了值 ‘chen’, yield 将被 chen 替换,因此 firstName 的值变为 chen

赋值后,代码继续执行,直到再次遇到 yield 并在此处暂停:

var secondName = yield;

第三次调用 next 时,原理和第二次相同,传入的 xiansheng 将替换 yield 并赋值于 secondName,接着执行:

console.log(firstName + secondName)

所以控制台将打印出 chenxiansheng

5.使用 Generator 处理异步调用

看下面的代码例子:

let generator;
let getDataOne = () => {
    setTimeout(function () {
        // 调用Generator并传递数据
        generator.next('dummy data one')
    }, 1000);
}
let getDataTwo = () => {
    setTimeout(function () {
        generator.next('dummy data two')
    }, 1000);
}
function* main() {
    let dataOne = yield getDataOne();
    let dataTwo = yield getDataTwo();
    console.log("data one",dataOne)
    console.log("data two",dataTwo)
}
// 创建一个Generator实例
generator = main();

在控制台输入 generator.next() 触发 main 函数执行,将打印出以下结果:

generator.next()

 [object Object]: {done: false, value: undefined}
 data one dummy data one  // 两秒后打印出
 data two dummy data two

main 代码看上去像在同步地调用getDataOne和getDataTwo,但两个调用是异步进行的

下面简单说一下整个运行过程:

首先,我们用 generator.next() 调用 main 函数执行,并遇到了第一个 yield :

let dataOne = yield getDataOne();

现在 Generator 进入了暂停模式,但是在暂停之前,它调用了 getDataOne 函数

let getDataOne = () => {
    setTimeout(function () {
        // 调用Generator并传递数据
        generator.next('dummy data one')
    }, 1000);
}

因此,当 Generator 暂停时, getDataOne 函数开始执行,这时,时间将会从1000倒数至0,也就是一秒后,将会执行下面这行:

generator.next('dummy data one')

这将会向 yield 语句返回 dummy data one ,因此 dataOne 变量变为 dummy data one ,一旦 dataOne 被赋值,代码将会继续执行到下一行:

let dataTwo = yield getDataTwo();

同理,当这行执行完毕后,我们得到了 dataOne 和 dataTwo :

dataOne = dummy data one
dataTwo = dummy data two

因为我们在 getDataOne 和 getDataTwo 各设置了1000毫秒后执行,所以控制台将会在两秒后同时打印出结果:

 data one dummy data one
 data two dummy data two

以上就是我要介绍的全部内容了,小伙伴们学习愉快!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章