小型JavaScript项目导入RxJS遇TypeError错误求助
问题
尝试在小型JavaScript项目的脚本文件中使用import导入RxJS,持续出现以下错误:
Subscriber.js:10 Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'rxjs')
HTML文件内容:
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="./styles/style.css"> <title>Load RxJs using import</title> </head> <body> <h1>Importing RxJs Lib</h1> <div> <h1 id="info">'loading ...'</h1> </div> <!-- <script src="https://unpkg.com/rxjs@7.5.7/dist/bundles/rxjs.umd.js"></script> --> <script src="./js/script.js"></script> </body> </html>
脚本文件内容:
// const updateUI = text => document.querySelectorAll('#info')[0].innerText = "finished"; const loadRxJsLib = async () => { await import('https://unpkg.com/rxjs@7.5.7/dist/bundles/rxjs.umd.js'); } document.addEventListener('DOMContentLoaded', (event) => { loadRxJsLib(); }); document.addEventListener('readystatechange', (event) => { if (document.readyState === 'complete') { const { range } = rxjs; const { filter, map } = rxjs.operators; range(1, 200) .pipe( filter((x) => x % 2 === 1), map((x) => x + x) ) .subscribe((x) => console.log(x)) } });
原因分析
- UMD包动态加载特性限制:你选用的是RxJS的UMD格式包,这类包通过script标签引入时会自动挂载到全局
window对象,但使用动态import()加载时,不会自动将rxjs暴露到全局作用域,导致后续代码访问rxjs变量时找不到目标。 - 执行时机不匹配:
readystatechange触发complete状态时,loadRxJsLib的异步加载操作大概率还未完成,此时rxjs变量尚未定义,直接访问必然报错。
解决方案
方案一:改用ES模块格式加载(推荐)
RxJS提供了ES模块版本,直接通过动态import导入所需内容,同时需要将脚本标记为模块类型:
- 修改HTML中的script标签,添加
type="module":
<script type="module" src="./js/script.js"></script>
- 更新脚本文件,导入ES模块版本的RxJS并执行逻辑:
const loadRxJsLib = async () => { // 导入RxJS核心模块和操作符 const { range } = await import('https://unpkg.com/rxjs@7.5.7/dist/esm/rxjs.min.js'); const { filter, map } = await import('https://unpkg.com/rxjs@7.5.7/dist/esm/operators.min.js'); range(1, 200) .pipe( filter(x => x % 2 === 1), map(x => x + x) ) .subscribe(x => console.log(x)); } document.addEventListener('DOMContentLoaded', () => loadRxJsLib());
方案二:手动挂载UMD包到全局
如果坚持使用UMD包,需要在动态加载后手动将模块内容挂载到window对象,并确保逻辑在加载完成后执行:
修改脚本文件:
const loadRxJsLib = async () => { const rxjsModule = await import('https://unpkg.com/rxjs@7.5.7/dist/bundles/rxjs.umd.js'); // 将RxJS挂载到全局window对象 window.rxjs = rxjsModule.default; // 加载完成后执行RxJS逻辑 const { range } = rxjs; const { filter, map } = rxjs.operators; range(1, 200) .pipe( filter(x => x % 2 === 1), map(x => x + x) ) .subscribe(x => console.log(x)); } document.addEventListener('DOMContentLoaded', () => loadRxJsLib());
方案三:直接用script标签引入UMD包(最简单)
如果不需要动态加载,直接恢复HTML中的script标签引入,去掉动态import逻辑即可:
- 恢复HTML中的注释代码:
<script src="https://unpkg.com/rxjs@7.5.7/dist/bundles/rxjs.umd.js"></script> <script src="./js/script.js"></script>
- 脚本文件简化为:
document.addEventListener('readystatechange', (event) => { if (document.readyState === 'complete') { const { range } = rxjs; const { filter, map } = rxjs.operators; range(1, 200) .pipe( filter(x => x % 2 === 1), map(x => x + x) ) .subscribe(x => console.log(x)) } });
内容的提问来源于stack exchange,提问作者Alte Schule
相关产品推荐
相关产品推荐

