Chr*_*ing 6 javascript performance memory-management iterable ecmascript-6
救命!我在C#编程很长一段时间后学会喜欢Javascript,但我学会爱上可迭代协议!
为什么Javascript采用需要为每次迭代创建新对象的协议?为什么要next()返回一个新的对象具有属性done和value代替采用类似C#这样的协议IEnumerable以及IEnumerator其在需要两个电话的费用不分配对象(一到moveNext,看看是否迭代完成,第二,以current获取价值)?
是否存在漏洞优化,跳过对象返回的分配next()?很难想象,假设迭代不知道一旦返回就可以使用该对象......
生成器似乎没有重用下一个对象,如下所示:
function* generator() {
  yield 0;
  yield 1;
}
var iterator = generator();
var result0 = iterator.next();
var result1 = iterator.next();
console.log(result0.value) // 0
console.log(result1.value) // 1
嗯,这是一个线索(感谢Bergi!):
我们稍后将回答一个重要问题(在第3.2节中):为什么迭代器(可选)在最后一个元素之后返回一个值?这种能力是元素被包裹的原因.否则,迭代器可以简单地在最后一个元素之后返回一个公开定义的sentinel(停止值).
并在Sect.3.2他们讨论使用Using generator作为轻量级线程.似乎说返回一个对象的原因next是,value即使done是,也可以返回true!哇.此外,可以生成return除了值yield和yield*-ing值和一个值,生成由return作为最终value时done是true!
所有这些都允许伪线程.而这个功能,伪线程,值得为循环中的每一次分配一个新对象... Javascript.总是如此意外!
虽然,现在我考虑一下,允许yield*"返回"一个值以启用伪线程仍然不能证明返回一个对象是正确的.该IEnumerator协议可以扩展后返回一个对象moveNext()的回报false-只需添加一个属性hasCurrent测试迭代完成后,当true指示current有一个有效的价值?
编译器优化并非易事.这将导致迭代器性能的相当大的变化......这不会导致库实现者出现问题吗?
在友好的SO社区发现的这个主题中提出了所有这些要点.然而,这些论点似乎没有成功.
但是,无论是否返回一个对象,迭代完成后都没有人会检查一个值,对吧?例如,大多数人都会认为以下内容会记录迭代器返回的所有值:
function logIteratorValues(iterator) {
  var next;
  while(next = iterator.next(), !next.done)
    console.log(next.value)
}
只是它不因为即使done是false迭代器仍然有可能返回另一个值.考虑:
function* generator() {
  yield 0;
  return 1;
}
var iterator = generator();
var result0 = iterator.next();
var result1 = iterator.next();
console.log(`${result0.value}, ${result0.done}`) // 0, false
console.log(`${result1.value}, ${result1.done}`) // 1, true
迭代器是在"完成"真的是迭代器之后返回一个值吗?单手拍手的声音是什么?这看起来很奇怪......
而这里是深入职位上的发电机我很喜欢.与迭代集合成员相反,花费大量时间来控制应用程序的流程.
另一个可能的解释是IEnumerable/IEnumerator需要两个接口和三个方法,而JS社区更喜欢单个方法的简单性.这样他们就不必引入符号方法组的概念,即接口......
是否存在漏洞优化,跳过对象返回的分配
next()?
是.那些迭代器结果对象很小,通常是短暂的.特别是在for … of循环中,编译器可以进行简单的转义分析,以查看对象根本不会面向用户代码(但只有内部循环评估代码).它们可以由垃圾收集器非常有效地处理,甚至可以直接在堆栈上分配.
以下是一些消息来源:
StopIteration异常迭代性能良好的关键是确保
iterator.next()循环中的重复调用得到很好的优化,并且理想地完全避免iterResult使用高级编译器技术的分配,如存储负载传播,转义分析和聚合的标量替换.为了真正发挥性能,优化编译器还应该完全消除iterator自身的分配-iterable[Symbol.iterator]()调用 - 并直接在迭代的后备存储上运行.