
JavaScript iterator patterns - loige
https://loige.co/javascript-iterator-patterns
======
anonytrary
One thing I dislike about the iterator protocol is that it creates garbage
around every value you're iterating over:

    
    
      let set = new Set([1,2,3]), it = set.values(), n;
      while(!(n = it.next()).done) console.log(n);
      // {value: 1, done: false}
      // {value: 2, done: false}
      // {value: 3, done: false}
    

I found this strange considering javascript has symbols now. Symbols would be
perfect for the iterator protocol:

    
    
      while((n = it.next()) !== Symbol.iteratorDone) console.log(n)
      // 1
      // 2
      // 3
    

Not that this is too much of an issue, I'm sure using yield/yield*/of will
eventually optimize this.

~~~
Klathmon
The generational garbage collectors in all (or the vast majority of)
javascript implementations is specifically tuned to make this a pretty big
non-issue for the extreme vast majority of code.

It's the same argument people make against many React patterns, that inline
objects or inline functions generate additional garbage, but when tested it's
found that the time spent cleaning up that garbage is insignificant (and in
the React case, workarounds often end up causing performance issues at boot
time by trying to move that garbage-generating code out of the render function
where it's a non-issue!)

Without measurements you are just guessing, and JITs don't always work the way
most will intuitively assume they work. I've tested the overhead of creating
and throwing away objects on each iteration of a loop, and the reality is that
it just doesn't impact the performance of the code in any meaningful way. The
GC happily cleans it up extremely fast, and in some cases the JIT will even
compile the code in a way to avoid generating the garbage at all.

~~~
fro0116
Agreed on all points, but I'd just like to point out the main reason inline
objects and inline functions is a perf antipattern in React is not garbage
collection pressure, but rather the fact that they invalidate perf
optimizations like PureComponent and React.memo because the objects/functions
will have new references on each render. If you use those two together, then
you're incurring the cost of individual prop comparisons used by
PureComponent/React.memo without reaping the benefit of being able to skip the
render entirely if no references have changed.

~~~
Klathmon
They are in that one case, but the vast majority of components aren't
PureComponent, and therefore it's not a universal "perf antipattern".

It's also one of those things that people tend to extrapolate out. They hear
that the function changing every render causes perf issues, and then just
assume it's truth and apply that thinking everywhere. It's so common that the
Hooks FAQ actually has a section dedicated to talking about this specifically
[1]!

We are getting off topic now, but it was one of the areas that I believe the
react team wasn't happy about when it comes to the design of React. You
had/have to treat components differently depending on whether they are pure or
implement `shouldComponentUpdate` and how they implement it.

It's also one of the things that the new Hooks API solves. With hooks like
`useMemo` and `useCallback` you can cache those values and functions that you
pass around.

[1] [https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-
becau...](https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-
creating-functions-in-render)

------
jondubois
Iterators and generators are powerful and can make code much cleaner/more
declarative. Especially when used with async/await.

If anyone is interested, I recently released a real-time WebSocket library
(Node.js and front end) which only uses Async Iterators to stream data (no
event listener callbacks):

[https://hackernoon.com/getting-started-with-asyngular-
bbe3dd...](https://hackernoon.com/getting-started-with-asyngular-bbe3dd1c716c)

Feedback welcome.

~~~
sephoric
As a cool example of the practicality of generators, my son and I wrote a
generator in PICO-8 (Lua calls it coroutines) to animate moving the tiles in a
2048 game we made, using simple a for-loop to animate the tile's pixel
coordinates, but yielding at the end of the loop body, so that we could let
_update() and _draw() continue. This allowed the program to still be able to
respond to key presses, which would "skip" to the end of an animation by fast-
forwarding the coroutine until it was dead, and then create and start the next
animation coroutine. I think when he saw that it was just a for-loop but it
that kept "pausing" (yielding) at the end of each iteration, he finally
understood generators.

------
guest124678
The next step I would have shown if I wrote this article, would have been to
tell reader that JS generators as they are now, do not work with async / wait.

As long as you have some simple Fibonacci interview question they look nice to
show off, but when you want to use them for real like return some paginated
data from server as on going iterator, then current JS generators cannot be
used.

This makes js generators limited for any real usage, given JS IO is async.

~~~
daxterspeed
Both async generator functions and async iterators have been in the pipeline
for a while. The proposed, and currently implemented syntax in Firefox and
Chrome is `for await ... of`[0]. Creating an async generator function is as
easy as `async function* functionName`.

[0]: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Statements/for-await...of)

Example of this syntax in practice:
[https://jsbin.com/folotu/edit?js,console](https://jsbin.com/folotu/edit?js,console)

~~~
haskman
You might be interested in a slightly unusual UI framework I wrote that
heavily focuses on async generators to define the UI -
[https://github.com/ajnsit/concur-js](https://github.com/ajnsit/concur-js).

The idea is that a UI "Widget" is a sequence of UIs (which themselves can be
Widgets) generated asynchronously (say when a UI event fires).

A sample widget -

    
    
        async function*() {
          // Show a clickable button.
          // All processing is async, this will conceptually block until button is clicked.
          yield* <button onClick>Click me</button>
          // Button was clicked, show text
          yield* <div>Button was clicked!</div>
        })
    

It uses React and VDOM to diff the UIs generated and update the page slightly
more efficiently. As you can see, it also provides JSX support (by overriding
createElement calls).

The Widgets themselves can be easily composed, and the entire thing is
designed to be extremely easy to get started with. The README on github has
more information.

------
sktrdie
If anybody is interested in coding in a way that is closer to requirements,
generators are really helpful to switch towards a paradigm called Behavioral
Programming: [https://lmatteis.github.io/react-
behavioral/](https://lmatteis.github.io/react-behavioral/)

~~~
bfrydl
Forgive me if I'm missing something but this looks needlessly complex. Could
you explain how this could be helpful, especially for developing React
applications? The page doesn't really explain it besides insisting that this
is closer to how we think, but I don't agree at all.

~~~
sktrdie
One of the things it helps with is the idea that we can modify the behavior
without having to actually see how old code has been implemented. All one
needs is a trace of events (a particular behavior) and can decide with newly
added code how to modify that trace to fit the new requirements (by blocking
specific traces and have others happen instead).

This is an extremely powerful way of programming because it more easily fits
how we develop apps: requirements constantly change. Currently when behavior
needs to be modified we are stuck with having to modify and understand old
code which can be very tedious (in my opinion it's a crucial pain-point in
software development).

Behavioral Programming makes it easier to modify a system without having to
understand _how_ it was built, but by observing a particular behavior. Once
observed, the behavior can be modified, removed or completely changed
_incrementally_ , without having to go back and refactor old code.

Sorry if it's very abstract. I gave a talk about it in case it helps:
[https://www.youtube.com/watch?v=_BLQIE-
_prc](https://www.youtube.com/watch?v=_BLQIE-_prc)

------
_xgw
> Consecutive calls to next() will always produce { done: true }.

Not necessarily. You can make recursive generators which never "terminate".
For example, here's a codegolfed version of a recursive generator which
represents a n + 1 sequence:

    
    
        p=function*a(x){yield x;yield*a(x+1)}(0)

~~~
loige
I meant there "[Once the generator has completed], Consecutive calls to
`next()` will always produce `{ done: true }`".

I should probably make it more explicit

PS: I like your n+1 example.

------
nicknaso
Good article thanks.

~~~
loige
Thank you, Nick I am really glad you liked it!

