编辑器白屏主因是误用async导致DOM未就绪,应改用defer或DOMContentLoaded监听;外链脚本需按序加defer、跨域资源加crossorigin="anonymous",内联初始化须显式等待DOM就绪。

在线编辑器(如 Monaco、CodeMirror)初始化失败、白屏、document.getElementById('editor') 返回 null,八成不是脚本没加载完,而是你误用了 async —— 它根本不管 DOM 是否就绪,下载完就执行。
为什么 async 会导致编辑器白屏
浏览器遇到 <script async src="monaco.js"></script> 时,会并行下载,但一旦完成就立刻执行。此时 HTML 解析可能才进行到 ,<div id="editor"> 还没被解析进 DOM,<code>document.getElementById('editor') 必然为 null。
常见报错包括:Cannot read property 'create' of undefined、MonacoEnvironment is not defined,尤其在 file:// 协议下更频繁——跨域限制导致错误堆栈被截断,调试只能靠猜。
-
async只适合完全独立的脚本,比如埋点 SDK(analytics.js),它不操作 DOM,也不依赖其他 JS - 编辑器主库 + 语言服务 + 主题配置 是强依赖链,
async会打乱加载顺序,触发require is not defined等模块错误 -
async对内联脚本无效,写成<script async>monaco.editor.create(...)</script>纯属浪费属性
defer 是编辑器外链脚本的默认选择
defer 脚本下载时不阻塞 HTML 解析,执行时机严格卡在 DOM 构建完成之后、DOMContentLoaded 触发之前,且按书写顺序执行——这正是编辑器初始化需要的确定性。
立即学习“前端免费学习笔记(深入)”;
但光加 defer 不够,必须满足三个条件:
- 所有外链脚本(
vs/loader.js、monaco-editor/min/vs/editor/editor.main.js)都带defer,且顺序不能错:loader 必须在 editor 主库之前 - 跨域资源(CDN 上的文件)必须声明
crossorigin="anonymous",否则 Chrome DevTools 里看不到完整错误详情 - 编辑器初始化代码(如
monaco.editor.create())不能直接写在defer脚本里——它得等前面所有defer脚本执行完才能调用;推荐封装成函数,在DOMContentLoaded回调中触发
内联初始化代码必须手动等 DOM 就绪
defer 属性对内联脚本无效,所以把 monaco.editor.create() 直接写在 <script defer></script> 标签里,和不加 defer 效果一样:执行时 DOM 很可能还没准备好。
正确做法是显式监听 DOM 就绪:
<script>
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('editor');
if (container) {
monaco.editor.create(container, { /* options */ });
}
});
</script>或者更稳妥地判断状态:
- 检查
document.readyState === 'loading'时挂监听 - 已是
'interactive'或'complete'时直接执行 - 避免在
head里放任何依赖body元素的内联脚本
ESM 模块可简化流程但有新约束
如果用的是 monaco-editor 的 ESM 版本(type="module"),浏览器会自动以 defer 行为加载,无需手动加 defer 属性:
<script type="module" src="./init-editor.js"></script>
但要注意:
- ESM 不支持
document.write(),旧式 loader 注入方式失效 -
import()动态导入需自行捕获异常:import('./monaco.js').catch(e => console.error('加载失败', e)) - 语言服务(如 TS Worker)仍需在
monaco.editor.create()后按需import(),不能指望它随主模块一起加载
真正容易被忽略的,是跨域资源缺 crossorigin 导致的静默失败——控制台只报 Failed to load module,没有堆栈,查半天发现只是少了一个属性。



















