TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Why would anyone need JavaScript generator functions?

247 点作者 lewisjoe超过 2 年前

46 条评论

jitl超过 2 年前
You can use One Weird Trick with generator functions to make your code &quot;generic&quot; over <i>synchronicity</i>. I use this technique to avoid needing to implement both sync and async versions of some functions in my quickjs-emscripten library.<p>The great part about this technique as a library author is that unlike choosing to use a Promise return type, this technique is invisible in my public API. I can write a function like `export function coolAlgorithm(getData: (request: I) =&gt; O | Promise&lt;O&gt;): R | Promise&lt;R&gt;`, and we get automatic performance improvement if the caller&#x27;s `getData` function happens to return synchronously, without mystery generator stuff showing up in the function signature.<p>Helper to make a function that can be either sync or async: <a href="https:&#x2F;&#x2F;github.com&#x2F;justjake&#x2F;quickjs-emscripten&#x2F;blob&#x2F;ff211447f403031cc7c2dcf484173a177cecf7a9&#x2F;ts&#x2F;asyncify-helpers.ts#L18-L26" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;justjake&#x2F;quickjs-emscripten&#x2F;blob&#x2F;ff211447...</a><p>Uses: <a href="https:&#x2F;&#x2F;cs.github.com&#x2F;justjake&#x2F;quickjs-emscripten?q=yield*+language%3ATypeScript" rel="nofollow">https:&#x2F;&#x2F;cs.github.com&#x2F;justjake&#x2F;quickjs-emscripten?q=yield*+l...</a>
评论 #33507301 未加载
评论 #33513835 未加载
评论 #33511218 未加载
评论 #33508615 未加载
jfengel超过 2 年前
Generators are a fairly natural way to write recursive descent parsers. The alternatives are either to parse everything and return it in one big structure (which can be awkward for large documents) or to supply Visitors (which works, but often doesn&#x27;t match your mental model).<p>It&#x27;s nice to be able to write &quot;a lexer just yields a stream of tokens&quot; and &quot;expr ::= term op expr&quot; as:<p><pre><code> function* expr() { x = term(); operator = op(); y = expr(); yield apply(operator, x, y); } </code></pre> Backtracking takes a little setup, but overall it&#x27;s a very elegant way to write code.<p>Not many people really need to write parsers, but even if you&#x27;re using a black box from somebody else, it can be fairly elegant to use if it supplies it as an AST generator or result generator.
评论 #33509351 未加载
评论 #33511020 未加载
评论 #33511809 未加载
评论 #33510304 未加载
drawfloat超过 2 年前
Not sure about the timtam example. Couldn&#x27;t this:<p><pre><code> const flow = (...fns) =&gt; x0 =&gt; fns.reduce( (x, f) =&gt; f(x), x0 ); function slamTimTamsUsingFlow(timtams) { return timtams .slice(0, MAX_TIMTAMS) .map(flow( biteArbitraryCorner, biteOppositeCorner, insertInBeverage, drawLiquid, insertIntoMouth)); } </code></pre> Just be written as:<p><pre><code> const slamTimTams = timtams =&gt; timtams .slice(0, MAX_TIMTAMS) .map(timtam =&gt; timtam.biteArbitraryCorner() .biteOppositeCorner() .insertInBeverage() .drawLiquid() .insertIntoMouth()); </code></pre> Feels much more concise and readable than the flow example
评论 #33508329 未加载
评论 #33506962 未加载
评论 #33508430 未加载
评论 #33509630 未加载
评论 #33506724 未加载
评论 #33514463 未加载
the_other超过 2 年前
Redux-sagas[0] makes great use of generators. I found it a fantastic tool, if you&#x27;re already in the redux ecosystem, and have an application that sprawls enough to benefit. It&#x27;s great when you have to manage multiple process lifecycles. A single &quot;saga&quot; can summaries an entire service lifespan in just a few lines of code. Good candidates include a socket connection, a user session, analytics etc. I desperately want to use it with my current project (streaming video) but our code&#x27;s too mature to introduce such an architectural change.<p>The downsides are:<p>- a quirky syntax that needs learning, and is of the &quot;loose with semantics&quot; style - like Rails-eque REST&#x27;s play with HTTP methods<p>- it&#x27;s hard to test (despite what the documentation claims). It&#x27;s highly declarative, and such code seems hard to test.<p>[0] <a href="http:&#x2F;&#x2F;redux-saga.js.org&#x2F;" rel="nofollow">http:&#x2F;&#x2F;redux-saga.js.org&#x2F;</a>
评论 #33509106 未加载
评论 #33514897 未加载
评论 #33506861 未加载
评论 #33509584 未加载
评论 #33506764 未加载
gbuk2013超过 2 年前
I&#x27;m a bit surprised that database query pagination isn&#x27;t directly mentioned as one of the use cases. The (async) generator wraps the paginated calls to the DB and yields pages or individual documents &#x2F; rows. It&#x27;s about as vanilla-CRUD-API scenario as I can think of.
评论 #33509397 未加载
评论 #33509110 未加载
munificent超过 2 年前
My favorite use case for generators (I was using C# at the time, but it applies equally well to any language with yield) was for implementing a turn-based game loop:<p><a href="http:&#x2F;&#x2F;journal.stuffwithstuff.com&#x2F;2008&#x2F;11&#x2F;17&#x2F;using-an-iterator-as-a-game-loop&#x2F;" rel="nofollow">http:&#x2F;&#x2F;journal.stuffwithstuff.com&#x2F;2008&#x2F;11&#x2F;17&#x2F;using-an-iterat...</a>
评论 #33513055 未加载
ravenstine超过 2 年前
I initially liked the idea of generators, but after years of trying to find ways to apply them, I just haven&#x27;t found a use case where they were more sensible than using existing logic and looping constructs. They <i>could</i> be useful where they would provide less overhead than constructing arrays for the same purpose, but that doesn&#x27;t mean the same thing can&#x27;t be achieved without either of those things. It&#x27;s good in theory, but hasn&#x27;t been useful to me in practice.
评论 #33508904 未加载
评论 #33509165 未加载
评论 #33513711 未加载
scotty79超过 2 年前
Because it&#x27;s an awesome and easy way to create iterables.<p><pre><code> class FreakyCollection { [Symbol.iterator]() { return function*() { for &#x2F;&#x2F;... &#x2F;&#x2F; iterate over your freaky collection however you please yielding one element by one }(); }</code></pre>
评论 #33507118 未加载
评论 #33512495 未加载
Waterluvian超过 2 年前
Python is where I developed my (naturally flawed but possibly useful) mental model for generators: you are &quot;pulling&quot; data out of them.<p>Instead of pushing data into a processing grinder, watching the sausage links pour out the other side, whether you&#x27;re prepared or not, you&#x27;re pulling each sausage on-demand, causing the machine to move as a consequence of wanting an output.<p>I&#x27;m sure smarter people appreciate generators more than I do. They&#x27;re useful for co-routines and other wizardry. But I personally just find the mental model more useful in some cases, especially knowing it keeps memory and CPU usage more in-line with my needs. Doubly especially if my generator may not have an upper bound.
评论 #33507565 未加载
rezonant超过 2 年前
I used generators to increase the performance of bitstream parsing by several orders of magnitude over using a promise based system<p><a href="https:&#x2F;&#x2F;github.com&#x2F;astronautlabs&#x2F;bitstream#generators" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;astronautlabs&#x2F;bitstream#generators</a>
qsort超过 2 年前
They were introduced when JS went through its &quot;let&#x27;s copy python&quot; phase.<p>They&#x27;re kind of crippled because generators only really become useful if you have the equivalent of itertools to build a sort of iterator algebra. I love generator-based code in python but it&#x27;s hard to replicate that without having the library too.
评论 #33508959 未加载
Sniffnoy超过 2 年前
I&#x27;ve used JS generator functions at work. Part of it is redux-saga, which has already been mentioned, but part of it is another use.<p>We use generators to implement functions that can make requests to the caller for more information. So the caller f calls the generator function g, creating an iterator, and then calls iter.next(...) in a loop. If the result is not done then the return value is a request from g to f for more information, which f supplies. If the result is done then g has returned a value and f can use it.<p>The reason we do this is actually an architectural one. In this case, the extra information supplied by f to g comes from an external network, and g lives in an internal library that we don&#x27;t want making any network requests or having any networking dependencies. My boss came up with this solution, and so far it&#x27;s worked out pretty well for us!<p>Note that before we split things up like this, g did make network requests directly, so g was async and its code was full of awaits. After switching it to this new structure, the awaits just became yield*s. :) (And the actual network requests themselves became yields.)
评论 #33514365 未加载
BigJono超过 2 年前
All you did was turn 15 lines of reasonably readable functional code (that, as another comment pointed out, can be done in 8) into 31 lines that were much harder to read.
评论 #33507687 未加载
_greim_超过 2 年前
I&#x27;ve found generators to be a great way to keep separate concerns separate. Now you can have a function whose job is to figure out what the next thing is, then consume it eslewhere as a simple sequence.<p>In the past I&#x27;d have a function accept a `visit(x)` callback, but then I had to invent a protocol for error handling and early cancellation between the host and callback.<p>The ability to just `yield x` and have done with it is a breath of fresh air.
jtolmar超过 2 年前
In games, you can use a generator function for stuff that&#x27;s supposed to take multiple frames. Saves you from either having to write a whole state machine system, or extracting all the state for every multi-frame action out into the object.
评论 #33511489 未加载
评论 #33513863 未加载
irrational超过 2 年前
My main takeaway from this is that I need to find a place to buy TimTams in the USA.
评论 #33507119 未加载
whycombinetor超过 2 年前
Strictly speaking, there&#x27;s no reason anyone &quot;needs&quot; generator functions. Instead of pausing the function execution at each `yield` statement, you can just write a regular (non-generator) function that returns a struct including all the local variables used in the function, and repeatedly call the function with the returned struct as the first argument (or `reduce`). Admittedly this is just writing the exact mechanism of yield in a different way just to avoid using `yield`, but that&#x27;s the point, it&#x27;s not necessary to have it built in to the language.
评论 #33507172 未加载
评论 #33513882 未加载
javajosh超过 2 年前
You can <i>kinda</i> define generators with an arrow function, kinda:<p><pre><code> const foo = (function*() { yield 1; })(); console.log(foo.next().value); </code></pre> I&#x27;ve only written one generator in &quot;real life&quot; and ended up replacing it anyway:<p><pre><code> &#x2F;&#x2F; A generator function that returns a rotating vector function* circlePath(stepsPerRotation = 60, theta = 0) { while (true) { theta += 2 * Math.PI &#x2F; stepsPerRotation; yield [Math.cos(theta), Math.sin(theta)]; } }</code></pre>
评论 #33507330 未加载
ramesh31超过 2 年前
I classify generators along with switch statements and while loops in JS. Perfectly fine to use if you know what you’re doing, but generally a code smell that belies further non-idiomatic code.
评论 #33507224 未加载
评论 #33506703 未加载
评论 #33508218 未加载
vanderZwan超过 2 年前
Combine them with a decent coroutine library and you can write relatively straightforward singlethreaded concurrency code. Ramsey Nassr has been exploring that:<p>[0] <a href="https:&#x2F;&#x2F;merveilles.town&#x2F;@nasser&#x2F;107892762993715381" rel="nofollow">https:&#x2F;&#x2F;merveilles.town&#x2F;@nasser&#x2F;107892762993715381</a><p>[1] <a href="https:&#x2F;&#x2F;jsbin.com&#x2F;mupebasiro&#x2F;edit?html,console,output" rel="nofollow">https:&#x2F;&#x2F;jsbin.com&#x2F;mupebasiro&#x2F;edit?html,console,output</a>
评论 #33509892 未加载
nikeee超过 2 年前
The author mentions iterator helpers [1], which could make stuff easier.<p>However, there is also a different proposal that touches different similar issue which might fix this too: The bind operator proposal [2].<p>Like the name implies, it allows to set the `this` for a function call. This opens the possibility to implement the common map&#x2F;filter&#x2F;reduce functions in a lazy manner _for arrays_. Taken from the samples, this could evaluate lazily on an array returned by `getPlayers()`.<p><pre><code> import { map, takeWhile, forEach } from &quot;iterlib&quot;; getPlayers() ::map(x =&gt; x.character()) ::takeWhile(x =&gt; x.strength &gt; 100) ::forEach(x =&gt; console.log(x)); </code></pre> Of course, this could also be used for iterators. However, the binding operator is not very active any more.<p>[1]: <a href="https:&#x2F;&#x2F;www.proposals.es&#x2F;proposals&#x2F;Iterator%20helpers" rel="nofollow">https:&#x2F;&#x2F;www.proposals.es&#x2F;proposals&#x2F;Iterator%20helpers</a> [2]: <a href="https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposal-bind-operator" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposal-bind-operator</a>
评论 #33519451 未加载
grose超过 2 年前
I found async generators to be handy while porting a C Prolog interpreter to WASM&#x2F;JS. A `for await` loop is a natural way to iterate over query results, and as a bonus you can use `finally` within the generator to automatically clean up resources (free memory). There are ways for determined users to leak (manually iterating and forgetting to call `.return()`) but I&#x27;ve found that setting a finalizer on a local variable inside of the generator seems to work :-). I can&#x27;t say manual memory management is a common task in JS but it did the trick.<p>The generator in question, which is perhaps the gnarliest JS I&#x27;ve ever written: <a href="https:&#x2F;&#x2F;github.com&#x2F;guregu&#x2F;trealla-js&#x2F;blob&#x2F;887d200b8eecfca8ed6e83cecd2ca384ee28d1c0&#x2F;src&#x2F;prolog.js#L77" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;guregu&#x2F;trealla-js&#x2F;blob&#x2F;887d200b8eecfca8ed...</a>
talkingtab超过 2 年前
Transducers. See Richard Hickey&#x27;s talk about transducers here: <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=6mTbuzafcII" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=6mTbuzafcII</a><p>You can implement transducers in JavaScript using generators. It was somewhat mind bending but fun.
dimgl超过 2 年前
So I keep seeing Sinclair&#x27;s blog posts both on &#x2F;r&#x2F;javascript, and this is the first time I see it on Hacker News.<p>While I appreciate the effort needed to write one of these posts, I can&#x27;t help but think about the amount of bad code that these blog posts are inspiring.
no_wizard超过 2 年前
If generators were treated as first class concerns in JS, they&#x27;d be so much more useful, but for them to be useful <i>today</i> you have to do alot of work to make it so in my opinion. We need iterator helpers to make them more useful built in to the standard language.
Pandavonium超过 2 年前
&gt; Arguably, Australia’s greatest cultural achievement is the Tim Tam.<p>After eating half a packet with my cuppa this morning (and feeling somewhat queasy for it), I can confirm timtams are one of our finest accomplishments.
wefarrell超过 2 年前
I do wish that JS had more builtin syntactic sugar around generators (and particularly async generators). They would be a lot more convenient and syntactically cleaner if most of the Array builtins could also be used for iterators. For async iterators the builtins would need to leverage the promise builtins as well, so you could to something like:<p><pre><code> const result = await asyncIterator.map(doSomethingAsync).reduce(asyncAggregatorFn) </code></pre> Without ever having to load all of your data into memory.
评论 #33511441 未加载
评论 #33510855 未加载
评论 #33513887 未加载
评论 #33510907 未加载
Frotag超过 2 年前
You can also implement context managers &#x2F; try-with-resources via generators. Not that I&#x27;ve seen it in the wild or recommend it. I remember it being annoying to debug for some reason.<p><a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;62879698&#x2F;any-tips-on-context-manager-similar-to-python-in-javascript" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;62879698&#x2F;any-tips-on-con...</a>
rbalicki超过 2 年前
For a concrete example, Relay uses them to garbage collect data in an asynchronous fashion. If an update is detected during the course of a gc, it is aborted.<p><a href="https:&#x2F;&#x2F;github.com&#x2F;facebook&#x2F;relay&#x2F;blob&#x2F;main&#x2F;packages&#x2F;relay-runtime&#x2F;store&#x2F;RelayModernStore.js#L567" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;facebook&#x2F;relay&#x2F;blob&#x2F;main&#x2F;packages&#x2F;relay-r...</a>
sktrdie超过 2 年前
Generators are a fun use-case for bthreads since they allow to &quot;cut&quot; through other modules and control their execution: <a href="https:&#x2F;&#x2F;medium.com&#x2F;@lmatteis&#x2F;b-threads-programming-in-a-way-that-allows-for-easier-changes-5d95b9fb6928" rel="nofollow">https:&#x2F;&#x2F;medium.com&#x2F;@lmatteis&#x2F;b-threads-programming-in-a-way-...</a>
jongjong超过 2 年前
I started using async generators years ago and using for-await-of loops to consume streaming data and be guaranteed that the processing order is maintained when there are async operations to be performed on each chunk of data. It&#x27;s difficult to do in any other way; you&#x27;d need some kind of queue structure which would make code very difficult to read.
8note超过 2 年前
I really like using generators in test code for setting mock&#x2F;stub.<p>You can be really specific about how you want it to run, without having to memorize a new language of function calls that have to be triggered in specific orders
oefrha超过 2 年前
Async generators should be a very natural interface for many event-based APIs, e.g. WebSocket.onmessage. Unfortunately converting a callback-based API to an async generator is highly nontrivial.
评论 #33511767 未加载
sbf501超过 2 年前
I use them for reading large files that need to be parsed.<p>A token might require a complex decode, so the generator fires once per token, but keeps the state of the file structure and the parser.<p>It greatly simplifies the code.
andrewstuart超过 2 年前
I rarely use generators but used one the other day.<p>I had some code that needed to deal out the next in a sequence of URLs, to functions that were triggered by events occurring at random times.
vbezhenar超过 2 年前
I used generator to iterate over AWS objects with automatic paging. Code was very compact and easy to read and write. Other approaches would be worse.<p>I don&#x27;t think I ever used it again.
kaleidawave超过 2 年前
It’s silly how the ‘async’ function modifier got a <i>keyword</i> before the function keyword and the generator modifier got a symbol ‘*’ after the function keyword…
oneeyedpigeon超过 2 年前
&gt; Some people might find the Australian and British accents difficult to understand.<p>Or even recognise; Graham Norton has an <i>Irish</i> accent, not British.
apineda超过 2 年前
I use them to iterate over structs in WASM memory that are neatly packaged as an &quot;object&quot;, but are just getters into the current offsets.
AtNightWeCode超过 2 年前
Block &#x2F;assets&#x2F;book-bg.jpg or remove the background from body::before to make it readable. Article still probably about JS.
az_reth超过 2 年前
Halfway through the article I completely forgot that it was about JavaScript, and I could only think about Tim Tams
kderbyma超过 2 年前
Paging, Streaming, Loops, Coroutines between asynchronous systems, queues, and state machines, emulators, etc.
swalsh超过 2 年前
Can I ask what kind of Tea goes best with Tim Tams? Are we talking about just simple black Earl Grey here?
teucris超过 2 年前
&gt; Repeat until there are no more Tim Tams, or you feel physically ill.<p>Similar to consumption of generator functions.
nilslindemann超过 2 年前
I like generators and using them in for (... of ...) {...} loops. Reminds me of Python joy.
heloitsme22超过 2 年前
Have you ever seen the rain?