第六章|迭代、数据流与二进制
上一章研究一次异步结果,本章研究一串结果。先学同步迭代协议,再让每次拉取能够等待,随后进入数据流中的字节表示与共享存储。三部分分别回答“下一项怎样获得”“生产速度怎样受控”“这一段数据如何解释”。
- 迭代器与生成器:可重复遍历、暂停恢复、委托与提前关闭。
- 异步迭代与 Streams:按需生产、背压、锁与取消。
- 二进制与共享内存:视图、字节序、编码、转移与原子同步。
同步和异步迭代是阅读主线;共享内存需要 Worker 与宿主配置知识,可以首次理解边界后再回读。它仍是本书正式内容,不以“进阶”之名省略。
阅读前把“值”和“下一项”区分开
前置知识是 Symbol、Promise 和 async/await。数组保存一组值,迭代器保存取得下一项的进度,异步迭代器把这个下一项的结果放进 Promise。三个层次叠起来,才得到 for await...of,不是给 for 循环随意加一个 await。
这里另一个贯穿概念是资源寿命:消费者不再需要数据时,生产者如何得知?同步迭代的 return、生成器 finally、流的 cancel 都在回答这个问题,只是各自负责的资源不同。结束循环、释放读取锁、取消底层请求不可互相代替。
迭代关闭需要特别慢读:return是一次协议请求,生成器可能在finally继续暂停;异步生成器还可能先等待当前next完成。Streams中的cancel同样要由底层源履行,释放锁仅改变读取所有权。看到“结束”二字时,先问结束的是哪一个层次。
本章包含一处有意保留的版本对照:for await消费同步生成器的拒绝Promise,在Node22与更新规范实现中可能有不同关闭行为。例子明确标注预期差异,并给出在异步生成器自身管理失败与清理的写法。学习新版规则与维护旧运行时需要同时保留这两条信息。
从一项数据走到一块内存
异步迭代决定何时拿到块,Streams 决定块如何排队以及压力如何传播,二进制视图决定块里的字节怎样解释。网络收到一个块,不保证它是一行文字或完整字符,所以编码边界需要自己的状态。即使调用顺序完全正确,用错字节序仍然会读出错误数值。
共享内存放在最后,是因为它改变了此前“同一 agent 中同步代码不会被另一个回调从中间打断”的前提:不同 Worker 可以同时访问共享数据。学到这里再讨论 Atomics,才能知道它解决哪一种竞争,也不会把普通异步竞态和多线程读改写混为一谈。
读完以后动手检查
读完后,应能实现不会提前计算所有值的筛选器,让提前退出沿迭代链清理,并把任意分块文本恢复成记录、把带偏移的字节视图解析成独立负载。第四题分别检验惰性、分块边界和所有权;通过输出与状态断言核对,而不只复述协议名称。