JavaScript iterator patterns
loige.co
loige.co
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.I don't know if that would be much of a problem in practice but it feels wrong instinctively.
[1,2, Symbol.iteratorDone, 3]
which would definitely break on something like that. It would seem the only real way to fix this is with a distinct wrapper.PHP's iterators have separate methods for advancing to the next element, checking if there's a current element, and getting the current element. That's cumbersome, and requires keeping extra state, but it's abstracted over so it doesn't typically matter. I think it mimics a bizarre old way of iterating through arrays.
There are multiple ways to signal the end. Javascript's is pretty clean.
Doing it like that would be out of place in many languages with different sensibilities, but it fits ok in Python.
It also helps that you rarely deal with StopIteration exceptions directly or even have to remember they're used under the hood.
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.
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...
This is why I get so disheartened when writing "benchmarks" for code. I don't know much about what gets transformed to what under the hood, and I think you can only write confident benchmarks if you know these things. I'm sure I've spent hours writing completely pointless benchmarks.
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...
Feedback welcome.
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.
[0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Example of this syntax in practice: https://jsbin.com/folotu/edit?js,console
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.
It's actually preferred over async/await in the frontend world in libraries such as redux-saga and mobx flow. One advantage is that you can cancel the iteration early.
Worked perfectly for me on Node.js 10.
This is actually in Node.js current, check out stream docs: https://nodejs.org/api/stream.html#stream_readable_symbol_as...
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
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)I should probably make it more explicit
PS: I like your n+1 example.