代码之家  ›  专栏  ›  技术社区  ›  A.A

为什么迭代器在for…中中断后关闭。。。循环?

  •  1
  • A.A  · 技术社区  · 1 周前

    我有一台可以生产1000件物品的发电机。我注意到,当我使用 for...of 循环部分消耗生成器,然后脱离循环,迭代器似乎关闭了。因此,我的后续 为了。。。属于 循环不会从第一个停止的地方继续。

    代码如下:

    function* test() {
      const array = Array.from({ length: 1000 }, (_, index) => index);
    
      for (let item of array) {
        yield item;
      }
    }
    
    const iterator = test();
    console.log('Before first loop', iterator);
    
    let j = 0;
    for (const i of iterator) {
      console.log('A', i);
    
      if (j++ === 3) {
        break; // Break after consuming 4 items
      }
    }
    
    console.log('Before second loop', iterator);
    
    j = 0;
    for (const i of iterator) {
      console.log('B', i);
    
      if (j++ === 3) {
        break;
      }
    }

    这是日志:

    Before first loop test {<suspended>}
    A 0
    A 1
    A 2
    A 3
    Before second loop test {<closed>}
    

    我原以为第二个循环会从第一个循环中断的地方继续,但事实并非如此。据我所知, 为了。。。属于 使用迭代器,除非明确重置,否则应继续迭代。

    • 为什么打破第一个 为了。。。属于 循环关闭迭代器?
    • 确切地说 does for...of 与发电机的生命周期相互作用?
    • 是否有办法在不切换到的情况下防止这种关闭 next() ?

    我明白我可以手动拨打电话 next() 在发电机上,但我特别问的是如何 为了。。。属于 在这种背景下工作。

    1 回复  |  直到 1 周前
        1
  •  2
  •   KLASANGUI    1 周前

    朋友,正如文件中所说 for..of/break :

    生成器实现return()方法,该方法使生成器函数在循环退出时提前返回。这使得生成器在循环之间不可重复使用。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#specifications

    Iteration protocols :

    <Iterator>.prototype.return(value) 可选:一个接受零个或一个参数并返回符合Iterator Result接口的对象的函数,通常其值等于传入的值,done等于true。调用此方法告诉迭代器,调用者不打算再进行任何next()调用,可以执行任何清理操作。当内置语言功能调用return()进行清理时,值总是未定义的。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#returnvalue

    因此,当您在迭代生成器迭代器的循环中调用断点时 return() 将被呼叫,发电机将被清理。

    这就是为什么生成器函数创建的迭代器关闭并且不能重用。

    下面有一个迭代任何迭代器的另一种方法的例子,就像你自己的例子一样:

    function * test ()
    {
        for ( let index = 0; index <= test.limit; index ++ )
        {
            yield index;
        }
    };
    
    test.limit = 1000;
    
    const iterator = test();
    let counter;
    
    counter = 0;
    
    while ( counter <= test.limit )
    {
        if ( counter ++ >= 3 ) break;
        
        console.log('Iteration value:', iterator.next().value);
    }
    
    counter = 0;
    
    while ( counter <= test.limit )
    {
        if ( counter ++ >= 3 ) break;
        
        console.log('Iteration value:', iterator.next().value);
    }
    
    // Then, if you want to clear the iterator:
    iterator.return(); // returns `undefined`.
    console.log('Iterator cleared after 6th loop (from 0 to 5).');
    
    for ( const value of iterator )
    {
        // This entire block will never be executed.
        console.log('Iteration value (after 5):', value);
    }
    .as-console-wrapper { min-height: 100%; }