You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于《JavaScript权威指南》中Promise版setInterval两种实现的疑问

关于《JavaScript权威指南》中Promise模拟setInterval的迭代器版与生成器版差异的误区解析

先还原书中两种clock函数的典型实现,再拆解差异和你的理解误区:

生成器版clock的问题根源

生成器版的代码通常是这样:

function* clockGenerator(interval) {
  let count = 1;
  while (true) {
    yield new Promise(resolve => {
      setTimeout(() => {
        resolve(count++); // count在定时器触发时才递增
      }, interval);
    });
  }
}

当你连续调用三次next():

  • 第一次调用:生成器执行到yield,创建第一个Promise,延迟interval,此时count仍为1;
  • 第二次调用:生成器从上次yield处继续,直接创建第二个Promise,延迟还是interval,count依旧是1;
  • 第三次调用:同理,第三个Promise的延迟还是interval,count保持1;
    三个定时器的触发时间几乎完全一致,所以三个Promise会同时resolve,此时count才会依次递增,但结果就是三个Promise几乎同时完成。

迭代器版clock为什么不会有这个问题

迭代器版(异步迭代器)的代码通常是这样:

function clockIterator(interval) {
  let count = 0;
  return {
    [Symbol.asyncIterator]() { return this; },
    next() {
      count++; // 调用next()的瞬间就递增count
      return new Promise(resolve => {
        setTimeout(() => {
          resolve({ value: count, done: false });
        }, interval * count);
      });
    }
  };
}

这里的核心是:count的递增操作在创建Promise之前就同步完成了,和Promise的resolve时机完全无关。

哪怕你在第一个Promise resolve前连续调用三次next():

  • 第一次next():count变成1,Promise延迟interval*1;
  • 第二次next():count变成2,Promise延迟interval*2;
  • 第三次next():count变成3,Promise延迟interval*3;
    每个Promise的延迟时间在调用next()时就已经确定,是依次递增的,所以它们会分别在interval、2*interval、3*interval后先后resolve,不会出现同时完成的情况。

你的理解误区

你误以为迭代器版的count是在Promise resolve时才递增,但实际上迭代器的next()方法是同步执行count更新的——只要调用next(),count就立刻加1,后续的Promise延迟时间直接基于更新后的count值计算,完全不受前一个Promise是否resolve的影响。这就是迭代器版不会出现多个Promise同时完成的原因。

内容的提问来源于stack exchange,提问作者Taofeek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:48:39