关于《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
相关产品推荐
相关产品推荐

