Here is an efficient, short solution using JS generators. JSfiddle
// Consecutive integers
let nats = function* (n) {
while (true) yield n++
}
// Wrapper generator
let primes = function* () {
yield* sieve(primes(), nats(2))
}
// The sieve itself; only tests primes up to sqrt(n)
let sieve = function* (pg, ng) {
yield ng.next().value;
let n, p = pg.next().value;
while ((n = ng.next().value) < p * p) yield n;
yield* sieve(pg, (function* () {
while (n = ng.next().value) if (n % p) yield n
})())
}
// Longest prefix of stream where some predicate holds
let take = function* (vs, fn) {
let nx;
while (!(nx = vs.next()).done && fn(nx.value)) yield nx.value
}
document.querySelectorAll('dd')[0].textContent =
// Primes smaller than 100
[...take(primes(), x => x < 100)].join(', ')
_x000D_
<dl>
<dt>Primes under 100</dt>
<dd></dd>
</dl>
_x000D_