反应:加载脚本需要很长时间,无法使用

时间:2019-04-24 11:54:11

标签: javascript reactjs

我正在尝试像这样在<head>中加载外部脚本:

<script async type='text/javascript' src='//externalprovider.net/our_script.js'></script>

此脚本声明了一个函数window.manager.loadFunction(sid, mid);,然后将其用于某些组件,如下所示:

componentDidMount() {
    window.manager.loadFunction(this.props.ids[0], this.props.ids[1]);
}

我的问题是,从外部提供程序获取脚本的速度很慢,因此该组件有时间在脚本准备好之前挂载。这给出了错误Uncaught TypeError: Cannot read property 'loadFunction' of undefined

仅需检查,我复制了完整内容并将其粘贴到<head>中,该脚本可以按预期工作。所以我的结论是,脚本从外部提供程序加载的速度太慢。不幸的是,这对我们不起作用,因为外部提供程序需要能够动态更改脚本,所以我无法在我们的<head>中对其进行硬编码。

所以我认为我应该提供一个使用axios加载脚本然后对其进行评估的服务,如下所示:

async getAdsScript() {
    try {
        const url = '//externalprovider.net/our_script.js';
        const src = (await axios.get(url)).data;
        const head = document.getElementsByTagName('head')[0];
        const newScriptTag = document.createElement('script');

        newScriptTag.type = 'text/javascript';
        newScriptTag.async = true;
        newScriptTag.text = src;
        head.appendChild(newScriptTag);

        PubSub.publish('AdsScript.loaded', true);
    } catch (error) {
        console.warn(error);
    }
}

然后我要像这样使用它:

loadFunction() {
    window.manager.loadFunction(this.props.ids[0], this.props.ids[1]);
}

componentDidMount() {
    PubSub.subscribe('AdsScript.loaded', (msg, showing) =>
        this.loadFunction());
}

但是这也不起作用,因为我收到了CORS错误Access to XMLHttpRequest at 'https://externalprovider.net/our_script.js' from origin 'https://dev.testserver.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.,我们很遗憾不能要求他们将CORS策略添加到他们的服务器中。

有人知道我该如何解决吗?

2 个答案:

答案 0 :(得分:1)

是的,正如您已经回答的那样,您只需从脚本标记中删除async属性即可。但是,在加载外部脚本之前,您的页面将被阻止。如果您与外部服务器的连接速度较慢,则可能会导致应用程序的初始化速度变慢。

如果要执行JS代码并渲染应用程序直到加载外部脚本,则可以执行以下两项操作之一:

  1. 您可以使用您所编写的代码并在您的身边设置Nginx,以将请求代理到外部服务器。之后,您将向Nginx请求获取外部代码。这样可以解决CORS的问题。

OR

  1. 您可以使用Deferred等待外部脚本加载。您可以在npm的某个lib中找到Deferred或自己编写。这就是它的样子:
<script>
    function Deferred() {
        let resolve = null;
        let reject = null;
        const promise = new Promise((res, rej) => {
            resolve = res;
            reject = rej;
        });
        return {
            promise,
            resolve,
            reject
        }
    }

    window.waitForExternalScript = Deferred();

    function onExternalScriptLoad() {
        window.waitForExternalScript.resolve();
    }
</script>
<script type="text/javascript" src="./your_main_script_here.js"></script>
<script async type="text/javascript" src="//externalprovider.net/our_script.js" onload="onExternalScriptLoad()"></script>

然后在您的应用中:

componentDidMount() {
    window.waitForExternalScript.promise.then(() => {
        window.manager.loadFunction(this.props.ids[0], this.props.ids[1])
    })
}

答案 1 :(得分:0)

显而易见的答案是从async的脚本标签中删除<head>

<script type='text/javascript' src='//externalprovider.net/our_script.js'></script>

我没看到那是因为我对代码的其他部分视而不见。