5

In ES6, is there any possible to clone an iterator states?

var ma=[1,2,3,4];
var it=ma[Symbol.iterator]();
it.next();

if I want to remember here the it states how should I do in javascritp?

what is remebered in it? since the

JSON.stringify(it) //it would just return {}
user504909
  • 9,119
  • 12
  • 60
  • 109

4 Answers4

4

It's not possible to clone an iterator. Iterator state is basically completely arbitrary and any given iterator may require or produce side effects (e.g. reading from or writing to a network stream) which are not repeatable on demand.

Ryan Cavanaugh
  • 209,514
  • 56
  • 272
  • 235
4

You can’t clone an arbitrary iterator, but you can create many distinct iterators from one by holding onto some state:

function tee(iterable) {
    const source = iterable[Symbol.iterator]();
    const buffers = [[], []];  // substitute in queue type for efficiency
    const DONE = Object.create(null);

    const next = i => {
        if (buffers[i].length !== 0) {
            return buffers[i].shift();
        }

        const x = source.next();

        if (x.done) {
            return DONE;
        }

        buffers[1 - i].push(x.value);
        return x.value;
    };

    return buffers.map(function* (_, i) {
        for (;;) {
            const x = next(i);

            if (x === DONE) {
                break;
            }

            yield x;
        }
    });
}

Usage:

const [a, b] = tee(iterator);
assert(a.next().value === b.next().value);
Ry-
  • 218,210
  • 55
  • 464
  • 476
0

I built a library that allows you to fork an iterator here: https://github.com/tjenkinson/forkable-iterator

Means you can do something like:

import { buildForkableIterator, fork } from 'forkable-iterator';

function* Source() {
  yield 1;
  yield 2;
  return 'return';
}

const forkableIterator = buildForkableIterator(Source());

console.log(forkableIterator.next()); // { value: 1, done: false }

const child1 = fork(forkableIterator);
// { value: 2, done: false }
console.log(child1.next());
// { value: 2, done: false }
console.log(forkableIterator.next());

// { value: 'return', done: true }
console.log(child1.next());
// { value: 'return', done: true }
console.log(forkableIterator.next());

If you no longer need to keep consuming from a fork providing you loose references to it there also shouldn’t be a memory leak.

Tom Jenkinson
  • 1,390
  • 3
  • 19
  • 43
0

It's not official yet, but I think there might be a solution in a stage 2 proposal for Iterator Helpers. If these methods don't affect the original iterator, then doing something like iter.take(Infinity) or iter.drop(0) would have the same effect as cloning.

Chris
  • 3,833
  • 3
  • 14
  • 11