caolan / highland

High-level streams library for Node.js and the browser
https://caolan.github.io/highland
Apache License 2.0
3.43k stars 147 forks source link

Debounce/Latest #434

Closed Announcement closed 8 years ago

Announcement commented 8 years ago

Eventstream Source, Debounced and Latest cracks your engine block.

var text, searches, results;

text = _("keyup", $("#searchbox"));
searches = text.debounce(1000).latest();
results = searches.map(lookup);

results.each(display);

function lookup(information) {
    return $(information.target).val();
}
function display(result) {
    console.log(result);
}

Steps to reproduce

  1. have an html with several articles and input#searchbox
  2. type some text, wait one second.
  3. start typing again...
  4. uh-oh!

Events

Streams can be used to handle events as well as data, control-flow and error propagation. This is often a convenient way to filter and combine events into groups, a common goal on dynamically updated sites.

Once we get inside the map/each everything seams to be all fine and dandy, but upon the SECOND trigger, chrome just throws a fit, even closing the dang tab becomes a pane and rendering the issue nearly impossible to debug.

Another fun fact. having to write

// what should work
_($("article")).map(information).each(response)
// what actually works
_(Array.prototype.slice.call($("article"), 0)).map(information).each(response)
vqvu commented 8 years ago

I'm not surprised. latest always emits the latest seen value. Even if it has already emitted that value and no new values have been emitted from the source.

A latest stream is meant to only be queried periodically, as mentioned by the docs.

Since each will query a stream for values as fast as the stream can emit it, what you have is roughly

var lastSeen;
_("keyup", $("#searchbox"))
    .debounce(1000)
    .each(function (x) {
        if (lastSeen == null) {
            setTimeout(loop, 0);
        }
        lastSeen = x;
    });

function loop() {
    while (true) {
        display(lookup(lastSeen));
    }
}

You probably just want debounce without latest.

The part about having to use Array.prototype.slice is annoying, but jQuery objects aren't arrays, so it's the expected behavior. You could do _($("article").toArray()), which is slightly fewer characters.

vqvu commented 8 years ago

I'm not sure if we should add support for array-like objects to the main stream constructor...we already do so much type coercion. Not to mention strings are array-like (in the sense that it has a length and integer subscript operator), so adding support might interfere with the EventEmitter coercion.

apaleslimghost commented 8 years ago

We support Iterators right? In jQuery 3 $ returns an Iterator.

vqvu commented 8 years ago

That's a good point. We do support both iterators and iterables.

Announcement commented 8 years ago

Closing in favor of jQuery 3 accessibility and Iterator support alternative. Thanks everyone!