【问题标题】:How to wait for another JS to load to proceed operation?如何等待另一个 JS 加载进行操作?
【发布时间】:2012-01-26 22:56:14
【问题描述】:

我有一个问题。我的一个 JS 脚本需要首先加载 Facebook SDK 和 Twitter 小部件 JS。 Facebook 创建FB 对象,Twitter 创建twttr 对象。他们俩都在我的脚本触发后创建这些对象,即使它们是从<head> 加载的。

我认为解决方案是定期检查是否定义了 FB 和 twttr,然后继续执行我的脚本。但我不知道该怎么做。

我尝试创建一个循环

while (typeof FB === 'undefined' || typeof twttr === 'undefined' || typeof twttr.widgets === 'undefined') {
    // run timeout for 100 ms with noop inside
}

但这显然不起作用,因为它会一直高速触发超时并且页面挂起。

请帮帮我,因为这个问题我睡不着。

【问题讨论】:

  • 我认为一定有问题...如果您将所有脚本放在 head 标签中,它们将按照您想要的顺序加载...所以写 FB 和编写脚本之前的 twitter 脚本......这应该是全部
  • +andreapier -- 它们并未全部加载到 中。如果您阅读 Facebook JS SDK 的说明,您会发现它们提供的代码必须是 中的第一件事。这是一个例子。

标签: javascript


【解决方案1】:

如果脚本以正常的同步方式加载,则只需确保 your <script> include 出现在 库之后文档的<head> 中的脚本。另一方面,如果这些脚本正在异步加载对象(似乎是这种情况),则创建如下内容:

function whenAvailable(name, callback) {
    var interval = 10; // ms
    window.setTimeout(function() {
        if (window[name]) {
            callback(window[name]);
        } else {
            whenAvailable(name, callback);
        }
    }, interval);
}

并像这样使用它:

whenAvailable("twttr", function(t) {
    // do something
});

twttr 定义在全局window 对象上之前,whenAvailable 的第二个参数中给出的函数不会执行。你可以对FB 做同样的事情。

重要提示:这些库可能还提供了一些内置方式来执行代码加载之后。您应该在它们各自的文档中查找此类钩子。

【讨论】:

  • 非常感谢。我使用了您的函数,但必须将条件修改为“if (typeof eval(name) !== 'undefined')”,因为它不适用于像 'twttr.widgets' 这样的名称
  • 你不应该使用 eval()
  • 宁可使用window.setIntevalwindow.clearInterval 而不是window.setTimeout 和递归:jsfiddle.net/2bubub2j,因为如果您选择use strict,那么您将遇到函数参数对象的问题。
  • 当然你不需要多个 setTimeouts 或匿名函数。这可以通过删除 window.setTimeout(function() { ... }, interval); 包装器来轻松简化,除非您希望它在第一次加载时异步运行,在这种情况下,您可以将 window.setTimeout(arguments.callee, interval); 替换为 whenAvailable(name, callback);
  • "arguments.callee" 不应再使用。 EcmaScript 5 禁止在严格模式下使用 arguments.callee。
【解决方案2】:

您是否已将脚本在页面加载时执行? (即body onload="do_this ();"

这应该会让你的代码在所有外部资源都被加载后执行。


关于setTimeout的使用

setTimeout 将立即返回,如果您想等待某个变量被定义,请使用以下内容。

function when_external_loaded (callback) {
  if (typeof FB === 'undefined' || typeof twtter === 'undefined') {
    setTimeout (function () {
       when_external_loaded (callback);
    }, 100); // wait 100 ms
  } else { callback (); }
}

...

when_external_loaded (function () {
    alert (FB);
    alert (twtter);
});

【讨论】:

    【解决方案3】:

    const checkIfLoaded = ('lib', cb) => {
      const interval = setInterval(() => {
        if (lib) {
          typeof cb === 'function' && cb();
          clearInterval(interval);
        } else {
          console.log('not yet');
        }
      }, 100);
    }

    【讨论】:

    • 能否改进缩进?
    • 您能解释一下代码是如何工作的吗?为什么'lib'在checkIfLoaded的参数中是一个字符串?谢谢!
    【解决方案4】:

    如果 Facebook 脚本是异步加载的,Facebook 有一种在库加载时执行代码的受支持方式,这应该比轮询更有效。例如,请参阅此答案:https://stackoverflow.com/a/5336483/816620

    如果 Facebook 脚本正在同步加载,那么您不必等待它们 - 它们会在运行后的任何其他脚本之前加载。

    【讨论】:

    • 嗯,是的,使用 FB 会更容易一些,因为它是明确启动的,但您无法控制 Twitter 代码。
    猜你喜欢
    • 2020-02-20
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 2015-11-09
    • 2021-08-16
    相关资源
    最近更新 更多