美文网首页
2023.29 生成器函数以及使用生成器实现async/awai

2023.29 生成器函数以及使用生成器实现async/awai

作者: wo不是黄蓉 | 来源:发表于2023-08-16 13:45 被阅读0次

大家好,我是wo不是黄蓉,今年学习目标从源码共读开始,希望能跟着若川大佬学习源码的思路学到更多的东西。

什么是生成器

生成器:是一种函数控制和使用的方案,可以让我们更加灵活的控制函数什么时候继续指向性、暂停执行等

如果已经执行完毕了,后面每次调用next的返回都是{ value: undefined, done: true }

有什么好处?

可以控制代码的执行,普通函数会将代码都执行一遍

表现形式:

  • 函数后面加个*

  • 代码执行可以被yield控制

  • 生成器函数默认在执行时,返回一个生成器对象

    • 要想执行函数内部的代码,需要生成器对象,调用他的Next操作
    • 当遇到yield时,会中断执行

举个例子:


function* helloWorldGenerator() {
    yield 'hello'
    yield 'world'
    return 'ending'
}

var hw = helloWorldGenerator()
console.log(hw) //返回一个生成器
console.log(hw.next())
//打印结果
Object [Generator] {}
{ value: 'hello', done: false }

next的时候可以传参

function* helloWorldGenerator() {
    console.log('111')
    const foo = yield 'hello'
    console.log(foo)
    const bar = yield 'world'
    console.log(bar)
    return 'ending'
}

var hw = helloWorldGenerator()
console.log(hw)
console.log(hw.next('i want wo say'))
console.log(hw.next('i want wo say1'))
console.log(hw.next('i want wo say2'))
console.log(hw.next('i want wo say3'))
//打印结果:
Object [Generator] {}
111
{ value: 'hello', done: false }
i want wo say1
{ value: 'world', done: false }
i want wo say2
{ value: 'ending', done: true }
{ value: undefined, done: true }

为什么第一次传参的next不起作用呢?

因为第一次调用next执行的代码是第一个yield之前的代码

参数接收是通过在yield之前获取的,如果想要第一次的时候传参,需要在调用helloWorldGenerator里面传参,在函数定义的地方接收参数

function* helloWorldGenerator(name) {
    console.log(name)
    console.log('111')
    const foo = yield 'hello'
    console.log(foo)
    const bar = yield 'world'
    console.log(bar)
    return 'ending'
}

var hw = helloWorldGenerator('i want wo say')
console.log(hw)
console.log(hw.next())
//打印结果:
Object [Generator] {}
i want wo say
111
{ value: 'hello', done: false }

生成器函数提前结束

使用throw或者return


function* getInfos() {
    const users = yield getUsers()
    console.log('users', users)
    throw Error('中断执行')
    // return
    const menus = yield getMenus()
    console.log('menus', menus)
}

const iterator = getInfos()

const result = iterator.next()
result.value
    .then((res) => {
        if (res.status) {
            console.log(res)
        }
    })
    .catch((err) => {
        console.log(err)
    })
const menus = iterator.next()
menus.value
    .then((resMenu) => {
        console.log(resMenu)
    })
    .catch((err) => {
        console.log(err)
    })

中断执行后,异步代码不会被执行到,在catch中捕获不到异常

生成器函数解决异步问题,解决回调地狱问题

实现异步:

function getUsers() {
    return new Promise((resolve) => {
        resolve({
            status: true,
            list: [
                { name: 'hp', age: 18 },
                { name: 'zhh', age: 18 }
            ]
        })
    })
}

function getMenus() {
    return new Promise((resolve) => {
        resolve({
            status: true,
            list: [
                { name: '一级菜单-1', pid: 0 },
                { name: '一级菜单-2', pid: 0 }
            ]
        })
    })
}

function* getInfos() {
    const users = yield getUsers()
    console.log('users', users)
    // throw Error('中断执行')
    // return
    const menus = yield getMenus()
    console.log('menus', menus)
}


const iterator = getInfos()

const result = iterator.next()
result.value.then((res) => {
    if (res.status) {
        console.log(res)
    }
})
const menus = iterator.next()
menus.value.then((resMenu) => {
    console.log(resMenu)
})

打印结果:

现在的代码可以实现按照同步编码的方式实现异步编程,但是每次都需要手动调用Netx如果上下有依赖关系,类似这样,是不是又有点回调地狱的意思


const iterator = getInfos()

const result = iterator.next()
result.value.then((res) => {
    if (res.status) {
        console.log(res)
        const menus = iterator.next()
        menus.value.then((resMenu) => {
            console.log(resMenu)
        })
    }
})

实现co方法解决手动调用的问题。


function co(fn) {
    const iterator = fn()
    function handleResult(result) {
        //已经迭代完了直接返回,没有迭代完递归调用
        if (result.done) return
        result.value
            .then((res) => {
                handleResult(iterator.next(res))
            })
            .catch((err) => {
                console.log(err)
            })
    }
    //默认执行一次
    handleResult(iterator.next())
}
co(getInfos)

上面代码使用递归实现依次调用问题

使用生成器实现async/await

使用async/await


async function fetchInfos() {
    const res = await getUsers()
    console.log(res)
    const resMenu = await getMenus()
    console.log(resMenu)
}
fetchInfos()
//打印结果:
{
  status: true,
  list: [ { name: 'hp', age: 18 }, { name: 'zhh', age: 18 } ]
}
{
  status: true,
  list: [ { name: '一级菜单-1', pid: 0 }, { name: '一级菜单-2', pid: 0 } ]
}

使用generator实现async/await

function run(gen) {
  //把返回值包装成promise
  return new Promise((resolve, reject) => {
    var g = gen()

    function _next(val) {
      //错误处理
      try {
        var res = g.next(val) 
      } catch(err) {
        return reject(err); 
      }
      if(res.done) {
        return resolve(res.value);
      }
      //res.value包装为promise,以兼容yield后面跟基本类型的情况
      Promise.resolve(res.value).then(
        val => {
          _next(val);
        }, 
        err => {
          //抛出错误
          g.throw(err)
        });
    }
    _next();
  });
}



关于使用generator实现`async/await`可以[参考](https://juejin.cn/post/6844904096525189128#heading-13)这篇文章,讲的很详细

相关文章

  • 使用生成器 --实现迭代协议

    目前来看,要在对象上实现可迭代功能,最简单的方式就是使用生成器函数。 使用示例:使用生成器函数,实现一个迭代器能够...

  • Generator

    生成器函数(Generator Function) 生成器函数不能直接作为函数来使用 执行生成器函数会返回一个生成...

  • php yield生成器

    yield生成器 介绍 一个简单的例子就是使用生成器来重新实现 range() 函数。 标准的 range() 函...

  • js ------ function* 生成器函数

    function* 生成器函数 文档 JS函数生成器,function* () {}, 项目中的使用情景

  • ES6:生成器(Generators)

    生成器 先看下面的例子 上面的函数就是生成器函数,和普通函数的不同在于: 使用function*定义生成器函数,而...

  • python 3.5 await async 的示范代码

    python3.5的话await只能在async装饰的函数内部使用,而且必须对一个协程/生成器类型的函数使用.这点...

  • python 生成器小结

    作者:邵正将 来源:PytLab 在python中生成器可以很方便的实现迭代协议。生成器通过生成器函数产生,生成器...

  • python 如何使用生成器函数实现可迭代对象?

    生成器对象和迭代器对象相似,支持 next()生成器使用关键字 yield生成器对象也是可迭代对象使用生成器函数的...

  • 生成器

    生成器 在python中,使用了yield的函数被称为生成器(generator)。生成器是一个返回迭代器的函数,...

  • 函数(四)生成器和promise

    1 生成器函数 定义和使用生成器 生成器函数能生成一组值的序列。显式地向生成器请求一个新的值,随后生成器响应一个新...

网友评论

      本文标题:2023.29 生成器函数以及使用生成器实现async/awai

      本文链接:https://www.haomeiwen.com/subject/qywkmdtx.html