
JavaScript Generators, Meet XPath - fanf2
https://jack.wrenn.fyi/blog/xpath-for-2020/
======
steelbrain
Great idea! Couple of things I would change here:

\- Instead of modifying prototype, which would pollute the environment for any
other modules to work with - use regular old functions

\- Instead of spreading the iterable to an array and then calling `.forEach`
on it, I would just iterate the source generator directly, it would look like:

    
    
        for (const node of xpath(el, 'xpath')) {
          node.textContent = node.textContent.replace("Hello", "Greetings")
        }

------
sktguha
I honestly don't see much the value of generators here. we can simply return
all the results directly from the xpath function that you created. Are there
any use case where you would want to stream the elements one by one ? you have
got all the results in memory anyways inside the xpath function

~~~
gridlockd
> you have got all the results in memory anyways inside the xpath function

Not necessarily, that's an implementation detail. The result of an XPath query
is not an array, it's some object that accepts integer indices for lookup.

If you were to return an array, there would be no way to break out of
iteration early without paying for every lookup. For something like XPath,
breaking out early is a likely scenario.

------
gridlockd
Please, using for loops is okay, _especially_ if you're not actually writing
functional code.

    
    
       [...document.xpath("//text()[contains(., 'Hello')]")]
            .forEach(node => node.textContent = node.textContent.replace("Hello", "Greetings"));
    
    

versus

    
    
        for (const node of document.xpath("//text()[contains(., 'Hello')]"){
            node.textContent = node.textContent.replace("Hello", "Greetings");
        }
    

No allocation of a pointless array, no redundant iteration, fewer "[]", "()"
and no "=>" or "...". No downside whatsoever!

~~~
RussianCow
> No downside whatsoever!

That's not entirely true if you need to support IE, in which case Babel (or
whatever compiler you're using) will generate extra code for the `for...of`
loop. But even then, I would still recommend using it for the reasons you
mentioned.

------
ricardobeat
Generators probably only add overhead here since there is nothing asynchronous
happening. You can just as well wrap the first version in a function and
return an array:

    
    
        xpath("//text()[contains(., 'Hello')]").forEach(...)

~~~
gridlockd
Generators/Iterators are not just for asynchronous code. Generators may be a
bit slower than iterating over an array, but arrays use more memory and put
more pressure on the garbage collector.

Your mileage will vary.

~~~
ricardobeat
True, though I suspect the impact in the case of a node list is negligible; in
quick tests I couldn't detect any meaningful difference even while looping
through 10k DOM elements.

------
baron816
I'd like to take this opportunity to plug my npm package
`fromable`([https://github.com/baron816/fromable](https://github.com/baron816/fromable))
which makes it easy an efficient to transform iterables and output the result
to any collection. It's kind of a `Array.from` meets transducers.

------
zeronone
I wonder if the risk of memory leak increases when using the generators.

------
k__
will the spread operator really evaluate the generator lazily?

~~~
Slackwise
Pretty sure it will not. Nothing is lazy in JS by default:

> One caveat of spreading iterables: JavaScript creates an array out of the
> elements of the iterable. That might be very wasteful for extremely large
> collections. For example, if we spread a large collection just to find an
> element in the collection, it might have been wiser to iterate over the
> element using its iterator directly.

> And if we have an infinite collection, spreading is going to fail outright.

[http://raganwald.com/2015/02/17/lazy-iteratables-in-
javascri...](http://raganwald.com/2015/02/17/lazy-iteratables-in-
javascript.html)

~~~
steelbrain
> Pretty sure it will not. Nothing is lazy in JS by default:

It really depends on the logic written. You can solve the same thing in many
different ways, the way chosen by the author doesn't seem to be a lazy one.

Not the language's fault. It's simply doing what is asked of it.

Eg, see
[https://news.ycombinator.com/item?id=24265507](https://news.ycombinator.com/item?id=24265507)

~~~
k__
Yes, I thought so too.

If they spread anyway, they could leave the generator away in the first place.

------
whereistimbo
XPath works best with XHTML

