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

在线编辑器(如 Monaco、CodeMirror)初始化失败、白屏、document.getElementById('editor') 返回 null,八成不是脚本没加载完,而是你误用了 async —— 它根本不管 DOM 是否就绪,下载完就执行。
为什么 async 会导致编辑器白屏
浏览器遇到 常见报错包括: 但光加 正确做法是显式监听 DOM 就绪: 或者更稳妥地判断状态: 如果用的是 但要注意: 真正容易被忽略的,是跨域资源缺 <script async src="monaco.js"></script> 时,会并行下载,但一旦完成就立刻执行。此时 HTML 解析可能才进行到 ,document.getElementById('editor') 必然为 null。Cannot read property 'create' of undefined、MonacoEnvironment is not defined,尤其在 file:// 协议下更频繁——跨域限制导致错误堆栈被截断,调试只能靠猜。
async 只适合完全独立的脚本,比如埋点 SDK(analytics.js),它不操作 DOM,也不依赖其他 JSasync 会打乱加载顺序,触发 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 主库之前crossorigin="anonymous",否则 Chrome DevTools 里看不到完整错误详情monaco.editor.create())不能直接写在 defer 脚本里——它得等前面所有 defer 脚本执行完才能调用;推荐封装成函数,在 DOMContentLoaded 回调中触发内联初始化代码必须手动等 DOM 就绪
defer 属性对内联脚本无效,所以把 monaco.editor.create() 直接写在 <script defer></script> 标签里,和不加 defer 效果一样:执行时 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>
document.write(),旧式 loader 注入方式失效import() 动态导入需自行捕获异常:import('./monaco.js').catch(e => console.error('加载失败', e))
monaco.editor.create() 后按需 import(),不能指望它随主模块一起加载crossorigin 导致的静默失败——控制台只报 Failed to load module,没有堆栈,查半天发现只是少了一个属性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











