【问题标题】:Javascript async generators changing type of yielded value?Javascript异步生成器改变产生值的类型?
【发布时间】:2020-01-24 00:28:48
【问题描述】:

所以我有一些生成器方法,它通过调用另一个方法来获取数据,该方法返回分页数据。此生成器迭代最近的缓冲区和yields 每个项目,直到没有更多可获取的数据。

async function* paginated_generator(source, opts = {}) {
    buffer = await source(opts)
    while (true) {
        for (let item of buffer.items) {
            yield item
        }
        if (!buffer.paging.next) {
            break
        }
        buffer = await source({ ...opts, next: buffer.paging.next })
    }
}

在这种情况下,它正在调用的方法如下所示,并为每条数据构造一个新的Notification 实例。

async notifications_paginated(opts = {}) {
    let Notification = require('./Notification')
    let instance = this || opts.instance

    let data = await paginated_data(`${instance.api}/news/my`, {
        limit: opts.limit || instance.paginated_size,
        key: 'news',
        prev: opts.prev,
        next: opts.next,
        headers: instance.headers
    })

    data.items = data.items.map((item) => new Notification(item))
    return data

}

当我直接从此方法获取数据,或者在生成器生成之前在生成器中插入类似console.log(item.some_getter) 的内容时,我可以看到该对象是Notification 类的一个实例。但是,如果我 await 生成器方法的下一个值,则它产生的数据无法访问附加到 Notification 对象的任何方法或 getter。

当这个数据从生成器返回时发生了什么变化?

【问题讨论】:

  • methods.paginated_data() 是对paginated_generator() 的引用吗?目前还不是很清楚。
  • @PatrickRoberts 是的。它们在不同的文件中,正在导入方法。
  • 您是否只是错过了它具有{ value: object, done: bool } 样式的事实。对于您的生成器,我认为与其使用 for 循环,不如返回 yield* buffer.items
  • @DieKaffir 这没有意义。对paginated_generator(…) 的调用会返回一个异步生成器实例,它可以(异步)迭代但不能awaited。这不是一个通过包含 .items 数组属性的值来实现的承诺。

标签: javascript node.js generator


【解决方案1】:

您没有正确使用异步生成器,但在我们开始之前,让我们稍微清理一下实现:

async function* paginated_generator(source, opts = {}) {
    let buffer = await source(opts)

    while (true) {
        yield * buffer.items

        if (!buffer.paging.next) return

        buffer = await source({ ...opts, next: buffer.paging.next })
    }
}

当您调用异步生成器函数时,它会返回一个异步生成器对象,该对象实现了异步迭代器和异步可迭代协议。

生成器函数和迭代协议的异步和同步对应物的语法和协议之间存在一些差异:

根据您提供的上下文,您的用法(可能)应该如下所示:

const Notification = require('./Notification')

async* notifications_paginated (opts = {}) {
    const instance = this || opts.instance
    const gen = paginated_data(`${instance.api}/news/my`, {
        limit: opts.limit || instance.paginated_size,
        key: 'news',
        prev: opts.prev,
        next: opts.next,
        headers: instance.headers
    })

    for await (const item of gen) {
        yield new Notification(item)
    }
}

然后,您可以将 notifications_paginated() 用作 Notification 对象的异步迭代器或异步迭代器。

如果您在返回之前尝试缓冲 notifications_paginated() 中的所有项目,那么您的 API 可能根本不使用分页,因为缓冲项目首先会破坏分页的目的。

【讨论】:

  • 感谢您的回答。不过,我使用 let 与您在此实现中将其更改为 const 之间是否存在重大区别?
  • 我想我应该包含它,但notifications_paginated 不会返回可以自己产生的东西。该数据来自这些方法paste.gg/p/anonymous/7fbe3e5d6b56469f99ba52459c38d915
  • @DieKaffir 所以paginated_generatorpaginated_data 不一样,正如你之前所说的那样?粘贴中的 paginated_data 与 OP 中的 paginated_generator 异步生成器函数有什么关系?
  • 哎呀,那是个错误。我误读了您的评论,并认为您指的是其他内容。 paginated_generatorpaginated_data 是不同的方法,做不同的事情。
  • @DieKaffir 那么您的问题实际上并不包含paginated_generator()用法?在那种情况下,我根本看不出第二个 sn-p 是如何相关的。
猜你喜欢
  • 2015-08-08
  • 2020-10-05
  • 1970-01-01
  • 1970-01-01
  • 2019-02-14
  • 2021-11-12
  • 2015-03-17
  • 2021-07-11
相关资源
最近更新 更多