一个 Promise 可以永远卡死:WebKit 的 bug 引出的 thenable 细节
来源:alistair.sh — 2026-11-14
📋 概述
一个在 Bun 与 Safari 上永远不结束的程序,暴露了 JavaScriptCore 处理 resolve(thenable) 的漏洞:getter 抛错本该让外层 promise 以该错误 reject,结果内层 promise 永远 pending。作者借此拆解 promise 的真实语义:resolve 不等于 settle,reject 简单而 resolve 复杂——因为 resolve 一个 thenable 要先取出它的 then,而属性读取可能触发 getter、可能抛异常,规范于是要求新建一对 resolve/reject、把 then 的调用排成微任务,并在抛出时 reject。
🔑 核心要点
- 一个「简单」的实现足以骗过直觉:把 resolve 当赋值是错的,resolve(thenable) 不是把它当值,而是要等它。
- 「resolved」不是规范状态,它只表示已被某个结果锁定,此刻完全可能还在 pending。
- 因为 then 可能抛错,引擎必须新建 resolve/reject 对并排队调用,而不是直接把外层函数交出去。
- Promise 本身就是 thenable(有 then),所以 thenable 的规则在 promise 上同样成立。
- 作者用「铁路」类比:fulfilled 与 rejected 是两条轨道,then 就是把轨道接下去的算子。
💡 金句
Once a promise is resolved to an outcome, it can absolutely still be pending.
← 返回 Lobsters 首页
👍 0
👎 0