首页 > 解决方案 > 检查脚本是否已加载(并且对象存在于窗口空间中)的最佳实践?

问题描述

本文帮助解释了浏览器如何拉入脚本,但是在尝试初始化对象之前检查对象是否存在的最佳实践是什么?

在此处链接 headroom.js 时,我目前正在检查窗口对象是否包含它。这可以吗,还是我应该使用某种形式的script.onload

<script src="js/main.js"></script>
<script src="js/libs/ScrollTrigger.min.js" defer></script>
<script src="https://unpkg.com/headroom.js@0.9.4/dist/headroom.min.js" async></script>

<script defer>
        document.addEventListener('DOMContentLoaded', function(){
            // setup ScrollTrigger (animate when item comes into view)
            var trigger = new ScrollTrigger({
                offset: {x:0, y:300},
                once: true
            });


            // bind Headroom to nav
            if(window.Headroom){
                init_headroom();
            }else{
                console.log('polling for Headroom '+Date.now());
                let poll_for_headroom = window.setInterval(function(){
                    if(window.Headroom){
                        clearInterval(poll_for_headroom);
                        init_headroom();
                    }
                },20);
            }


更多问题: 2a) 这种轮询会阻塞用户界面吗?2b) 我应该检查“ScrollTrigger.min.js”是否存在吗?

标签: javascriptparsingonload

解决方案


最佳做法是将load处理程序添加到script要检查其加载的标签:

const headroomScript = document.querySelector('script[src*="headroom"]');
headroomScript.onload = () => {
  console.log('Loaded!');
  console.log(typeof window.Headroom);
};
<script src="js/main.js"></script>
<script src="js/libs/ScrollTrigger.min.js" defer></script>
<script src="https://unpkg.com/headroom.js@0.9.4/dist/headroom.min.js" async></script>

要检查所有多个脚本何时加载,您可以使用Promise.all

// this will fail because the `src` of "js/main.js" does not exist in stack snippets:
const proms = [...document.querySelectorAll('script[src]')]
  .map(script => new Promise((resolve, reject) => {
    script.onload = resolve;
    script.onerror = reject;
  }));
Promise.all(proms)
  .then(() => {
    console.log('All scripts are loaded!');
    console.log(typeof window.Headroom);
  })
  .catch((err) => {
    console.log('There was an error');
  });
<script src="js/main.js"></script>
<script src="js/libs/ScrollTrigger.min.js" defer></script>
<script src="https://unpkg.com/headroom.js@0.9.4/dist/headroom.min.js" async></script>

// this will succeed:
const proms = [...document.querySelectorAll('script[src][async]')]
  .map(script => new Promise((resolve, reject) => {
    script.onload = () => {
      console.log(script.src + ' loaded');
      resolve();
    };
    script.onerror = reject;
  }));
Promise.all(proms)
  .then(() => {
    console.log('All scripts are loaded!');
    console.log(typeof window.Headroom);
    console.log(typeof window.jQuery);
  })
  .catch((err) => {
    console.log('There was an error');
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" async></script>
<script src="https://unpkg.com/headroom.js@0.9.4/dist/headroom.min.js" async></script>

请注意,async脚本的属性仅对具有外部的脚本有效src- 该属性对内联脚本没有影响,例如

<script async>
  // do some stuff
</script>

标签在async这里什么也不做。

这种方法和您原来的方法都不会阻塞 UI。


推荐阅读