Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine iterators #3

Closed
benjamingr opened this issue Jul 4, 2018 · 7 comments
Closed

Combine iterators #3

benjamingr opened this issue Jul 4, 2018 · 7 comments

Comments

@benjamingr
Copy link

Might be nice to have some methods that lets you combine two async iterators - concat zip etc.

@ali42
Copy link

ali42 commented Jul 5, 2018

@benjamingr
Copy link
Author

No, pipe combines combinators, not iterators

@jamiemccrindle
Copy link
Owner

@benjamingr could you provide an example usage?

@benjamingr
Copy link
Author

Some setup:

function once(target, eventName) {
  return new Promise(resolve => {
    function fn(e) { resolve(e); target.removeEventListener(e); }
    target.addEventListener(fn);
  });
}
// get a stream for clicks on an element
async function* clicks(target) {
   while(true) yield once(target, 'click');
}

// take n items from an iterator and then close it
async function* take(iterator, n) {
  for(let i = 0; i < n; i++) {
    const {done, value} = await iterator.next();
    if (done) return value;
    yield value;
  }
  iterator.return(); // signal done to the stream
}

Now for our combinators:

const clicksOnHeader = clicks(document.querySelector('header'));
const clicksOnFooter = clicks(document.querySelector('footer'));
// let's see some operators we might want to end
const clicksOnEitherHeaderOrFooter = merge(
  clicksOnHeader, 
  clicksOnFooter
);

const twoHeaderThenTwoFooter = concat(
  take(clicksOnHeader, 2),
  take(clicksOnFooter, 2)
);

for await(const e of clicksOnEitherOrFooter) {
  // triggers whenever the header or footer are clicked
}
for await(const e of twoHeaderThenTwoFooter) {
  // values: first two clicks on header and then two clicks on footer then close
} 

@jamiemccrindle
Copy link
Owner

Thanks!

@benjamingr
Copy link
Author

Sure! On a completely unrelated note - We are also gathering usage examples for async-iterators at Node.js core (here) and are working on giving users a better experience (here and here).

If you ever notice a case where the Node.js (or V8) behaviour is confusing or problematic please do bring it up so we can improve it. If you have any questions please do reach out as well (via email or on one of the above repos).

I also implemented some combinators "back then" and Kevin (who was proposal champion at the time) even made it run - it's quite old at this point though since it's from when the proposal was at an early stage - I might have updated it at some point :)

@jamiemccrindle
Copy link
Owner

jamiemccrindle commented Jul 7, 2018

Great. I'll feed back anything I find that could lead to a better experience.

I think you can do what you need with the current combinators (I added take). The logic is the same (I think) I just changed a few things:

  • using built in fromEvent
  • using built intake
  • split out the two cases or they would close each other's fromEvent clicks
  • concat syntax is slightly different (currying as opposed to args)
  • (used typescript... but that's not relevant)
import { fromEvent } from "axax/es5/fromEvent";
import { concat } from "axax/es5/concat";
import { merge } from "axax/es5/merge";
import { take } from "axax/es5/take";

async function twoClicks() {
  const clicksOnHeader = fromEvent(
    document.querySelector(".header") as HTMLElement,
    "click"
  );
  const clicksOnFooter = fromEvent(
    document.querySelector(".footer") as HTMLElement,
    "click"
  );

  const twoHeaderThenTwoFooter = concat(take(2)(clicksOnHeader))(
    take(2)(clicksOnFooter)
  );

  for await (const e of twoHeaderThenTwoFooter) {
    // values: first two clicks on header and then two clicks on footer then close
    console.log("clicked on two of header and footer");
  }
}

async function headerOrFooter() {
  const clicksOnHeader = fromEvent(
    document.querySelector(".header") as HTMLElement,
    "click"
  );
  const clicksOnFooter = fromEvent(
    document.querySelector(".footer") as HTMLElement,
    "click"
  );

  // let's see some operators we might want to end
  const clicksOnEitherHeaderOrFooter = merge(clicksOnHeader, clicksOnFooter);


  for await (const e of clicksOnEitherHeaderOrFooter) {
    // triggers whenever the header or footer are clicked
    console.log("clicked on either header or footer");
  }
}


document.addEventListener('DOMContentLoaded', () => {
  twoClicks();
  headerOrFooter();
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants