docs: 加一篇函数流走向

call-flow.md 讲的是三个阶段各自在做什么,缺的是**函数之间怎么串起来的**——
想改代码、想知道加一层该加在哪,没有一处能查。

docs/flow.md 七张图:

  全景            公开 API → 注册表 / 取 VM / 调用 三条链
  runner 三态     Script / Instance / staticTarget 的 acquire+finish 差别,
                  「同一实例串行」就是 acquire 到 finish 之间一直持着 i.mu
  newVM 内部      为什么 scope 是显式参数而不是从 ctx 嗅
  作用域进 VM      WithScope → vmGlobals → bind → lazyGlobal → freeze 五跳,
                  这是全库最容易看不清的一条链
  invoke 内部     含 defer 的注册顺序(finish → stop → recover,后进先出)
  lookup 三级     exports → ctor 静态 → 全局兜底,解释了 Script.Has 为什么
                  对静态方法也返回 true
  编译链          Prepared 为什么不是优化开关而是正确性要求

写的时候实地核对了每条断言,抓出三处我自己写错的:

  1. 图上把 Bundle → FinalizeBundle 画成两步,实际 Bundle 末尾自己就调了
  2. 把「省 44% 常驻内存」归因给惰性注入——那是关掉 console 的收益
  3. 「只读全局赋值静默失败」只对全局本身成立,freeze 拷出来的嵌套只读属性
     (store.Set = null)实测是抛错的

顺带修一处上一轮改名的残留:engine.go 的注释还指着 lazyglobal_test.go。
This commit is contained in:
2026-09-10 16:24:18 +08:00
parent 6477b27ef4
commit 0c947dde70
4 changed files with 296 additions and 1 deletions
+1 -1
View File
@@ -207,7 +207,7 @@ func (e *Engine) compileLocked(name, source, version string, prepared bool) (*Sc
//
// 注意产物里**没有** "use strict"esbuild 输出 ESM 格式时不加这个指令,
// wrapESM 包成 IIFE 时也没加。所以脚本跑在非严格模式下,后果之一是给只读
// 全局赋值会**静默失败**而不是抛错(见 lazyglobal_test.go 的断言)。
// 全局赋值会**静默失败**而不是抛错(见 engine_globals_test.go 的断言)。
//
// 想改成严格模式就把这里传 true,但那是行为变更:脚本里任何依赖非严格语义的
// 写法(给未声明变量赋值、with、八进制字面量……)都会开始报错。