【问题标题】:Is there a way to load a script tag and execute the script it contains after the page is fully loaded?有没有办法加载脚本标签并在页面完全加载后执行它包含的脚本?
【发布时间】:2020-10-25 14:40:02
【问题描述】:

我试图在页面加载到我的 html(或 php)页面后动态包含一个 three.js 模块类型的脚本标记。这是我需要的,因为 google pagespeed 洞察力在一个有三个 js 的页面上严重失败,导致页面出现错误和糟糕的速度分数。

  • 我已经尝试过 php readfile - 有效,但并没有真正改变速度测试的行为,我得到 LCP 的问号结果

  • 我正在考虑在页面加载后尝试使用 xhr 插入脚本,这可能是一个解决方案吗?

settimeout 在这里不是一个选项

有什么想法吗?

【问题讨论】:

  • 对,不要使用 settimeout,而是在 domcontentloaded 或 window on load 事件上执行 xhr,然后拉出该脚本
  • 你现在如何加载three.js?你能提供一个minimal reproducible example你的代码吗?
  • @Dshiz 继承页面:带有普通脚本标签:adambernath.com/lotto/lotto.html 带有 php 读取文件:adambernath.com/lotto/lotto5.php
  • @KresimirPendic 你能给我一个例子来说明如何做到这一点吗?我已经尝试过,到目前为止我无法让它工作,但我可能做错了什么。到目前为止我已经做到了:<script> function loadXMLDoc() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("demo").innerHTML = this.responseText; } }; xhttp.open("GET", "haromd.js", true); xhttp.send(); }; loadXMLDoc(); </script> <script type="module" id="demo"> </script>

标签: javascript php xmlhttprequest


【解决方案1】:

管理加载three.js 脚本的正确方法是使用requestIdleCallback()

一旦页面被加载并且浏览器窗口空闲,脚本就会开始加载。

例子:

function loadThreeJS(deadline){
    //your three.js script
}

requestIdleCallback(loadThreeJS)

您可以传入一个可选的超时参数,如果在超时时间内回调没有完成,它将重新排队等待下一个事件循环空闲时的回调。

requestIdleCallback(loadThreeJS, { timeout: 3000 })

可以在here找到文档。

另一种方法是使用 Promise 并在 DOMContentLoaded 事件之后加载脚本。

以下也使用requestIdleCallback(),但更具体到您的问题,因为它将脚本标签插入到文档中。借自here,直接在浏览器中使用:

如果您需要脚本元素具有type=module,请像这样设置选项变量:let options = {timeout: 3000, type: "module"}

let src = "https://cdnjs.cloudflare.com/ajax/libs/three.js/r121/three.min.js" // your three.js script file source
let options = {timeout: 3000}
document.addEventListener("DOMContentLoaded", function(event) {
    new Promise((resolve, reject) => {
        let { timeout } = options
        if (typeof timeout === 'number') {
        timeout = Math.max(timeout, 1)
    
        if (typeof requestIdleCallback === 'function') {
            requestIdleCallback(loadScript, {
            timeout
            })
            return
        }
    
        setTimeout(loadScript, timeout)
        return
        }
    
        loadScript()
    
        function loadScript () {
            const script = document.createElement('script')
            script.addEventListener('load', () => resolve(script))
            script.addEventListener('error', () => reject(new Error(`Failed to load script: "${src}"`)))
            if (options.type) script.type = options.type
            if (options.charset) script.charset = options.charset
            if (options.id) script.id = options.id
            if (typeof options.noModule === 'boolean') script.noModule = options.noModule
            script.async = options.async !== false
            script.defer = options.defer !== false
            script.src = src
            document.head.appendChild(script)
        }
    })
})

ThreeJS 脚本 CDN URL 的测试脚本加载时间为 15 毫秒。

【讨论】:

  • 我试过(这里:adambernath.com/lotto/lotto10.html)它加载速度很快,没有任何问题,但它仍然在谷歌页面速度洞察力上失败(现在出现 NO_FCP 错误,就像它通常包含在脚本标签中一样)感谢您的想法,但值得一试。还有其他方法可以解决这个问题吗?我还尝试了 xhr,它给出了 pagespeed 洞察力的结果,但没有 LCP。还有什么想法吗?
猜你喜欢
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
  • 2019-07-29
  • 1970-01-01
相关资源
最近更新 更多