Stop consuming a generator after enough values.

lazy-take-model A generator can describe a longer sequence while the caller decides how many values to read.

Lazy Take Model

take
lazy_take_model.js
Replay: real traced execution (multi-file project)
const take = 2;
const values = [];

function* squares() {
  let current = 1;
  while (current <= 5) {
    yield current * current;
    current = current + 1;
  }
}

for (const value of squares()) {
  if (values.length >= take) {
    break;
  }
  values.push(value);
}

console.log("take=" + take);
console.log("values=" + values.join(","));
const take = 1;
const values = [];

function* squares() {
  let current = 1;
  while (current <= 5) {
    yield current * current;
    current = current + 1;
  }
}

for (const value of squares()) {
  if (values.length >= take) {
    break;
  }
  values.push(value);
}

console.log("take=" + take);
console.log("values=" + values.join(","));
const take = 3;
const values = [];

function* squares() {
  let current = 1;
  while (current <= 5) {
    yield current * current;
    current = current + 1;
  }
}

for (const value of squares()) {
  if (values.length >= take) {
    break;
  }
  values.push(value);
}

console.log("take=" + take);
console.log("values=" + values.join(","));
  1. take ← 2, values ← (empty)

    1const take→ 2 = 2; //@take=1, 32const values→ (empty) = [];
  2. current ← 1

    1const take = 2; //@take=1, 32const values = [];34function* squares() {5  let current→ 1 = 1;6  while (current <= 5) {
  3. while (current <= 5)

    pass 1 of 3
    4function* squares() {5  let current = 1;6  while (current1 <= 5) {7    yield current * current1;8    current = current + 1;
    All 3 passes — pass 1 is the card above
    passcurrentvalues.lengthtake
    11
    22
    3322
  4. values ← 1, current ← 1

    5  let current = 1;6  while (current <= 5) {7    yield current→ 1 * current;8    current = current→ 2 + 1;9  }10}1112for (const value of squares()) {13  if (values.length >= take) {14    break;15  }16  values.push(value1);17}
    values this step(empty) 1values
  5. values ← 1,4, current ← 2

    5  let current = 1;6  while (current <= 5) {7    yield current→ 2 * current;8    current = current→ 3 + 1;9  }10}1112for (const value of squares()) {13  if (values.length >= take) {14    break;15  }16  values.push(value4);17}
    values this step1 1,4values
  6. if (values.length >= take)

    12for (const value of squares()) {13  if (values.length2 >= take2) {14    break;15  }
  7. console.log("take=" + take);

    16  values.push(value);17}1819console.log("take=" + take2);20console.log("values=" + values1,4.join(","));
    outputtake=2
    values=1,4
  1. take ← 1, values ← (empty)

    1const take→ 1 = 1;2const values→ (empty) = [];
  2. current ← 1

    1const take = 1;2const values = [];34function* squares() {5  let current→ 1 = 1;6  while (current <= 5) {
  3. while (current <= 5)

    pass 1 of 2
    4function* squares() {5  let current = 1;6  while (current1 <= 5) {7    yield current * current1;8    current = current + 1;
  4. values ← 1, current ← 1

    5  let current = 1;6  while (current <= 5) {7    yield current→ 1 * current;8    current = current→ 2 + 1;9  }10}1112for (const value of squares()) {13  if (values.length >= take) {14    break;15  }16  values.push(value1);17}
    values this step(empty) 1values
  5. while (current <= 5)

    pass 2 of 2
    4function* squares() {5  let current = 1;6  while (current2 <= 5) {7    yield current * current2;8    current = current + 1;
  6. if (values.length >= take)

    12for (const value of squares()) {13  if (values.length1 >= take1) {14    break;15  }
  7. console.log("take=" + take);

    16  values.push(value);17}1819console.log("take=" + take1);20console.log("values=" + values1.join(","));
    outputtake=1
    values=1
  1. take ← 3, values ← (empty)

    1const take→ 3 = 3;2const values→ (empty) = [];
  2. current ← 1

    1const take = 3;2const values = [];34function* squares() {5  let current→ 1 = 1;6  while (current <= 5) {
  3. while (current <= 5)

    pass 1 of 4
    4function* squares() {5  let current = 1;6  while (current1 <= 5) {7    yield current * current1;8    current = current + 1;
    All 4 passes — pass 1 is the card above
    passcurrentvalues.lengthtake
    11
    22
    33
    4433
  4. values ← 1, current ← 1

    5  let current = 1;6  while (current <= 5) {7    yield current→ 1 * current;8    current = current→ 2 + 1;9  }10}1112for (const value of squares()) {13  if (values.length >= take) {14    break;15  }16  values.push(value1);17}
    values this step(empty) 1values
  5. values ← 1,4, current ← 2

    5  let current = 1;6  while (current <= 5) {7    yield current→ 2 * current;8    current = current→ 3 + 1;9  }10}1112for (const value of squares()) {13  if (values.length >= take) {14    break;15  }16  values.push(value4);17}
    values this step1 1,4values
  6. values ← 1,4,9, current ← 3

    5  let current = 1;6  while (current <= 5) {7    yield current→ 3 * current;8    current = current→ 4 + 1;9  }10}1112for (const value of squares()) {13  if (values.length >= take) {14    break;15  }16  values.push(value9);17}
    values this step1,4 1,4,9values
  7. if (values.length >= take)

    12for (const value of squares()) {13  if (values.length3 >= take3) {14    break;15  }
  8. console.log("take=" + take);

    16  values.push(value);17}1819console.log("take=" + take3);20console.log("values=" + values1,4,9.join(","));
    outputtake=3
    values=1,4,9