You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JS中引入外部文件函数?插件加载后window对象为空求解

动态加载插件后window对象未更新的原因及解决办法

问题描述

我正在为一个库开发插件系统,通过Ajax从其他文件获取函数,使用Function构造函数包装并返回该函数后添加到window对象中,但循环执行完成后检查window对象却发现它是空的。相关代码如下:

x.html (主文件)

<html>
    <head>
        <script src="//cdn.jsdelivr.net/npm/eruda"></script><script>eruda.init();</script>
        <script>
            window.addEventListener('error', function(e) {
                console.error(e, e.message, e.filename, e.lineno, e.colno, e.error);
            });
            if (typeof window.example !== 'object') {
            window.example = {
                plugins: {}
            };
        }
        </script>
    </head>
    <body>
        Text
        <script type="module">
            import { loadPlugin } from "./y.js";
            await loadPlugin(['bold','italic']);
            console.log(window.example.plugins)
            console.log(window.example.plugins.italic)
        </script>
    </body>
</html> 

y.js (导入器)

export async function loadPlugin(plugins, namespace) {
    for (var i = 0; i < plugins.length; i++) {
        if (typeof window.example.plugins[plugins[i]] === 'undefined') {
            fetch(`z.js`)
            .then((response) => response.text())
            .then(function(code) {
                if (code.trim() !== '') {
                    try {
                        code += 'return theme;'
                        window.example.plugins[plugins[i]] = (new Function(code))();
                    } catch (err) {
                        console.log(err);
                    }
                }
            });
        }
        if (i === (plugins.length - 1)) {
            return new Promise(function(resolve) {
                resolve(window.example.plugins);
            });
        }
    }
}

z.js (待导入函数的文件,原标注为z.html需修正文件名)

function theme() {
    console.log('Hooray!');
}

问题原因

  1. 异步操作未等待,提前返回结果:fetch是异步操作,循环中没有等待fetch的回调执行完成,就直接返回了window.example.plugins。此时插件还未加载完成,所以对象为空。
  2. var变量的作用域问题:循环中使用var i,在fetch的then回调中,i会指向循环结束后的最终值(即2),导致所有插件都被错误地赋值到不存在的plugins[2]键上,而非预期的bold和italic。
  3. 文件路径不匹配:代码中fetch的是z.js,但提供的待导入文件标注为z.html,会导致获取的内容不符合预期,执行Function时可能出错。

解决办法

修改后的y.js代码

export async function loadPlugin(plugins, namespace) {
    const promises = [];
    for (let i = 0; i < plugins.length; i++) {
        const pluginName = plugins[i];
        if (typeof window.example.plugins[pluginName] === 'undefined') {
            // 收集每个fetch的Promise
            const loadPromise = fetch(`z.js`)
                .then(response => response.text())
                .then(code => {
                    if (code.trim()) {
                        try {
                            code += 'return theme;';
                            window.example.plugins[pluginName] = (new Function(code))();
                        } catch (err) {
                            console.error(`加载插件${pluginName}失败:`, err);
                        }
                    }
                })
                .catch(err => {
                    console.error(`请求插件文件失败:`, err);
                });
            promises.push(loadPromise);
        }
    }
    // 等待所有插件加载完成
    await Promise.all(promises);
    return window.example.plugins;
}

关键修改点

  • 用let声明循环变量,确保每个迭代的变量独立,避免作用域污染。
  • 收集所有fetch的Promise,通过Promise.all等待全部异步操作完成后再返回结果。
  • 修正变量引用,直接使用pluginName而非依赖循环变量i,避免回调中变量值不正确。
  • 添加错误捕获,便于排查请求或执行过程中的问题。
  • 确保待导入文件名为z.js,与fetch的路径一致。

内容的提问来源于stack exchange,提问作者Codemaster United

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:35:41