0

我正在使用 javascript 对页面提供时已经存在的 HTML 元素进行一些简单的更改(例如更改 div 元素的背景图像、添加 ID 等)。这当然适用于除 IE8 之外的所有浏览器,其中更改似乎没有反映在 DOM 中,因此当我在 JS 运行后解析 dom 时,它无法找到我正在寻找的元素。该页面由标题中的 2 个 javascript 文件组成,1 个是我无法控制的外部第三方脚本,但它是添加 id 和背景图像的那个。第二个是我的,它在第一个之后调用,正在解析文档以查找具有新 ID 的特定元素。两者都是外部脚本,不在 HTML 源代码中内联。

据我所知:

  • 竞争条件,2 个外部 Javascript 正在运行 1 个正在更改按钮并添加 id,另一个正在解析 dom 以查找特定元素,并且它们同时运行,第二个从未找到元素
  • 进行更改后,IE8 无法正确刷新 DOM

我的 JS 在头中的第一个 JS 之后被调用,因此您会假设阻塞不会导致竞争条件,并且在我的 JS 运行之前元素将可用

我尝试过的事情:

  • 我尝试在我的代码运行之前向正文添加一个类以强制刷新 DOM
  • 我使用了 IE8 开发者工具,id 和元素不存在,但是如果我刷新几次它们就会神奇地出现(此时页面已经完全加载,我可以完全与之交互)

有任何想法吗?

谢谢!

4

1 回答 1

1

要记住的一件事是,当您创建多个<script>标签时,您无法保证它们的加载顺序,并且取决于它们的构建方式 - 它们通常会在加载后立即开始处理。

因此,如果您在 CDN 中包含一个本地文件和一个文件,例如:

<script type="text/javascript" 
        src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
</script>
<script type="text/javascript" src="/js/my_script.js"></script>

您必须考虑到 CDN 文件的交付速度通常比托管文件快得多。在上述情况下,这可能是一件好事 - 因为jQuery在您的脚本之前加载到页面上可能是理想的 - 但是如果您正在加载不同的 3rd 方脚本,这可能依赖于您的脚本的 DOM 中存在的某些元素负责创建,您的脚本可能无法及时创建它们。

想象一下这个场景:

<script type="text/javascript" src="https://someurl/somelib.js">
    // This script parses the DOM and applies alterations to certain items
</script>
<script type="text/javascript" src="/js/my_script.js">
    // This script creates the DOM elements the other script is supposed to alter
</script>

仅当本地文件 , 首先加载时,您的页面才会起作用/js/my_script.js- 这不太可能,因为其他文件是从专用 CDN 提供的。

当两个文件都在本地提供时,情况会更糟,例如:

<script type="text/javascript" src="/js/my_relied_upon_script.js"></script>
<script type="text/javascript" src="/js/my_reliant_script.js"></script>

在这种情况下,这完全取决于您的本地 Web 服务器如何处理 HTTP 请求,以确定以什么顺序发生的事情。

所以 - 解决方案:

1) 让你的脚本都等待document'onready事件触发。因为此事件仅在文档完全加载后发生(包括完全加载其元素所需的任何其他 HTTP 请求,例如脚本、图像等) - 您可以保证脚本至少会等到完整的 DOM加载。

2) 使下级脚本等待触发事件。

使用 jQuery,一个示例可能类似于以下内容:

// Script #1
$(document).bind('ready', function () {
    $('#NeedsBackground').css({ background: 'url(/gfx/bg.png)' });

    var $wrapper = $('<div />').addClass('wrapper');
    $('#NeedsWrapper').wrap($wrapper);

    // Here's the magic that enforces loading.
    $(document).trigger('Script1Finished');
});

// Script #2
$(document).bind('Script1Finished', function () {
    $('.wrapper').css({ border: '1px solid #000' });
});

现在 - 请记住,上述转换是相当糟糕的,而不是您想要做的事情(例如内联 CSS 等,通常) - 但他们举了一个例子。因为Script #2要求.wrapper元素在运行之前存在,所以需要确保它在发生之后Script #1发生。

在这种情况下,我们通过trigger在文档上设置一个自定义事件来实现这一点,然后我们可以响应该事件 - 我们仅在 DOM 处于正确状态后触发该事件。

于 2012-07-24T22:48:18.747 回答