结论:SharedArrayBuffer 只影响「交互式输入」和「Stop」,不是「能不能 Run」的前提。拿不到就自动降级,不再抛 ReferenceError,宿主页永不加头也能正常跑。
Pyodide 跑在 Web Worker 里,主线程要把用户输入送进去(input()), 还要能异步打断正在执行的脚本(Stop)。这两件事靠共享内存 + Atomics 实现, 而共享内存就是 SharedArrayBuffer(SAB)。
浏览器规定 SAB 只在跨源隔离(cross-origin isolated)的文档里存在。 隔离状态由宿主页自己的响应头决定:
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: credentialless # 或 require-corp
onlinepy.com 自身已带齐这两个头,所以独立打开永远是全功能。 但被第三方页面用裸 iframe 嵌入时,iframe 的隔离性服从父文档—— 父页没有这两个头,iframe 里就同样拿不到 SAB。 注意 allow="cross-origin-isolated" 这个 iframe 属性只在父页本身已跨源隔离时才生效,父页没头写它也没用。
| 能力 | 跨源隔离(有 SAB) | 未隔离(自动降级) |
|---|---|---|
| 运行代码(Run) | ✅ 可用 | ✅ 可用 |
| 标准输出 / 报错输出 | ✅ 可用 | ✅ 可用 |
| 交互式 input() | ✅ 可用 | ⚠️ 返回空串,脚本继续跑完 |
| Stop(中断执行) | ✅ 立即中断 | ⚠️ 退化为「终止并重启 worker」 |
| 终端标题 | 常规显示 | 显示 non-interactive |
| 控制台报错 | 无 | 无(不再抛 ReferenceError) |
| 宿主页是否需要 COOP/COEP | 否(页面自身已带) | 否(自动降级) |
一句话:降级后 IDE 依然能跑、能出结果,只是用不了 input() 和 Stop。终端标题会显示 non-interactive(鼠标悬停有说明),输入框不会再出现, 避免「闪一下但没法输入」的假象。
detectSabCapability():先 typeof 判断,再真实分配一小块。 只看 typeof 不够——有些浏览器在没隔离时也暴露构造器,只有真分配才抛。stdin 不再进 Atomics.wait(无 SAB 时它本身也会抛), 直接返回空串,让脚本跑完而不是卡死,并回发一次提示。方案 A:什么也不做。 点 Run 就能跑,读者代码里没有 input() 就完全够用。
方案 B:给宿主页加头,换来完整功能。Netlify 建 public/_headers(与 _redirects 同目录):
/* Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: credentialless
注意:加了 COEP 后,页面上所有跨源资源(第三方 CDN、字体、图片)都要带Cross-Origin-Resource-Policy: cross-origin 或 Access-Control-Allow-Origin, 否则会被拦。站点接了第三方统计/广告且不好放行,就别加。
方案 C:免配置全功能。 改用 widget 气泡或 <onlinepy-ide> 自定义元素, 它们的面板本身就是跨源隔离的 iframe,父页零要求,input() 与 Stop 全可用。
<script src="https://onlinepy.com/embed.js"></script>
<onlinepy-ide code="print('Hello, World!')" features="run,output,theme"
style="width:100%;height:500px"></onlinepy-ide>把站点跑在一个刻意不返回 COOP/COEP 的本地服务上,复现「父页 + 裸 iframe」场景:
crossOriginIsolated: false、typeof SharedArrayBuffer === 'undefined',iframe 内同样拿不到——就是原报错现场。Hello, World!,控制台无 ReferenceError, 终端显示 non-interactive。input() 的脚本完整跑完(input() 得到空串), 只有一条 INFO 提示,不卡死。相关源码:src/hooks/usePyodide.ts(能力探测与降级)、public/pyodideWorker.js(非交互式 stdin)、src/components/IDE.tsx(non-interactive 提示)。
另见 首页 的嵌入说明与 Changelog。