【问题标题】:cCan DOM events fire before my script is executed?c可以在我的脚本执行之前触发 DOM 事件吗?
【发布时间】:2012-03-02 21:43:49
【问题描述】:

我有一个 video 元素和一个通过 jQuery 将 onplay 处理程序附加到视频的脚本:

<video id="vid" />
<!-- ... -->
<script type="text/javascript">
    $('#vid').on('play', function () {
        $(this).addClass('playing');
    });
</script>

根据this answer,,用户可能能够在脚本加载之前与视频播放器进行交互。但我需要确保在触发 onplay 事件之前附加我的事件处理程序。

为了测试这一点,我在 video 之后添加了一个调用 play() 的脚本。该处理程序在所有主流浏览器上运行,除了 WebKit,它根本不播放视频。即使将 jQuery 语句包装在 $().ready() 函数中,仍然可以在 onplay 之前附加处理程序。

是否保证我的脚本不会错过 HTML5 视频中的任何事件?这同样适用于所有 DOM 事件吗?如果我在脚本中添加async 会怎样?

【问题讨论】:

    标签: javascript html html5-video jquery-events


    【解决方案1】:

    这种情况下的竞争条件曾经是可能的:

    <video autoplay src="…"></video>
    <script>alert("wait!")</script>
    <script>$('video').on('play',…)</script>
    

    但是,为了缓解这个问题,规范已被更改。现在浏览器应该queue firing of events until next event loop run,而不是立即触发它们。

    如果附加事件处理程序的脚本是紧跟在&lt;video&gt; 之后的内联 脚本,无需等待 DOMReady,则在兼容的浏览器中不会发生竞争条件.

    如果你使用外部或异步脚本,等待 DOMReady,使用setTimeout 或同步 XHR,那么你可能会错过这些事件,因为这些事情会导致事件循环被处理(虽然我不能 100% 确定是否网络停顿允许浏览器处理事件循环)。


    我不知道 WebKit 是否已更新以支持更安全的行为。如果您仍然有问题,那么您可以使用即使在立即触发事件时也有效的方法:

    1. 使用内联事件处理程序:

      <video onplay="…">
      
    2. 以编程方式创建元素 (document.createElement('video')),并在元素插入文档之前附加处理程序。

    【讨论】:

    • 我在 iPad 上覆盖锚元素的点击事件时遇到了问题。如果我在呈现之前点击元素,即使我的事件处理程序总是阻止默认操作,它也经常导航离开。我最终使我的标记对 js 不友好,所以这不是问题。
    • 三年后我将重新审视这个问题,因为 Chrome 会在我的脚本附加事件处理程序之前在 source 元素上触发 error 事件。内联脚本不能保证竞争条件不会发生;事实上,如果我在脚本内部或之前添加一兆字节的空白,Chrome 将在下载空白时运行事件循环。
    【解决方案2】:

    确保这一点的最佳方法是使用 RequireJS,并确保在需要时以正确的顺序嵌套,或者使用 RequireJS 的 orderPlugin。

    现代化者优先。

    【讨论】:

    • 这样你可以添加模块和所有时髦的东西,并且在执行时只加载你需要的代码。
    • 这与问题到底有什么关系?
    • 这确保了在他的事件处理程序准备好之前视频播放器没有被加载......或者但是。这基本上消除了先加载内容的猜测。
    猜你喜欢
    • 2019-07-22
    • 2016-12-09
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 2012-04-05
    相关资源
    最近更新 更多