【问题标题】:jQuery's function $(function())’s execute order when the $(function()) called more one timesjQuery的函数$(function())在$(function())多次调用时的执行顺序
【发布时间】:2017-02-08 17:01:03
【问题描述】:

这样的代码:

$(window.document).ready(function () {
    window.alert('alert 1');
});

$(function () {
    window.alert('alert 2');
});

$(function () {
   window.alert('alert 3');
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo2</title>
    <script src="jquery-3.1.1.js"></script>
    <script src="demo2.js"></script>
</head>
<body>

</body>
</html>

当我执行上述代码时,页面的警报顺序有时是: 警报 1、警报 2、警报 3,有时是:警报 1、警报 3、警报 2。 谁能告诉我为什么?

【问题讨论】:

  • 您尝试了哪个版本的 jQuery?您可以在 plnkr plnkr.co 重现问题吗?
  • 我尝试执行10次似乎没问题。
  • 这是一个有效的jsfiddle.net/3pyxfjj5
  • 您的真实代码与问题中的代码完全一样吗?如果 you 运行问题中的代码,它会这样做吗?你有任何通过脚本加载器加载的脚本吗?
  • @freedomn-m 这种情况不可能发生。 DOM 就绪事件恰好在第 2 步之后触发。根据定义,如果有尚未解析的脚本,则 DOM 未就绪。

标签: javascript jquery jquery-3


【解决方案1】:

39303947 行处,jQuery 版本 3.1.1 处理在 document 已经加载后调用的 .ready()。在第 3938 行,jQuery.readysetTimeout 内部被调用,没有设置带有附加注释的持续时间

// Handle it asynchronously to allow scripts the opportunity to delay ready

这将解释如何在 window.alert('alert 2') 之前调用 window.alert('alert 3')


// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE <=9 - 10 only
// Older IE sometimes signals "interactive" too soon
if ( document.readyState === "complete" ||
    ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {

    // Handle it asynchronously to allow scripts the opportunity to delay ready
    window.setTimeout( jQuery.ready ); // Line 3938

} else {

    // Use the handy event callback
    document.addEventListener( "DOMContentLoaded", completed );

    // A fallback to window.onload, that will always work
    window.addEventListener( "load", completed );
}

以下 stacksn-p 应该重现 OP 描述的结果

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Demo2</title>
  <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
  <script>
    $(window.document).ready(function() {
      window.alert('alert 1');
    });

    $(function() {
      window.alert('alert 2');
    });

    $(function() {
      window.alert('alert 3');
    });
  </script>
</head>

<body>

</body>

</html>

另见completed函数3924

// The ready event handler and self cleanup method
function completed() {
    document.removeEventListener( "DOMContentLoaded", completed );
    window.removeEventListener( "load", completed );
    jQuery.ready();
}

请参阅版本 1 的 plnkr http://plnkr.co/edit/C0leBhYJq8CMh7WqndzH?p=preview


编辑、更新

为确保.ready() 处函数的执行顺序,您可以从函数调用中返回一个promise,在单个.ready() 调用中使用.then() 来调用全局或之前在.ready() 处理程序中定义的函数。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Demo2</title>
  <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
  <script>
    function ready1(wait, index) {
      // do stuff
      return new Promise(resolve => {
          setTimeout(() => {
            window.alert('alert ' + index);
            resolve(index)
          }, wait)
        })
        .then((i) => console.log(i))
    }

    function ready2(wait, index) {
      // do stuff
      return new Promise(resolve => {
          setTimeout(() => {
            window.alert('alert ' + index);
            resolve(index)
          }, wait)
        })
        .then((i) => console.log(i))
    }

    function ready3(wait, index) {
      // do stuff
      return new Promise(resolve => {
          setTimeout(() => {
            window.alert('alert' + index);
            resolve(index)
          }, wait)
        })
        .then((i) => console.log(i))
    }
    $().ready(function() {
      ready1(3000, 0) 
      .then(function() {
        return ready2(1500, 1) 
      })
      .then(function() {
        return ready3(750, 2) 
      });
    })
  </script>
</head>

</html>

【讨论】:

  • 使用setTimeout 排队的东西也会按顺序触发。我现在没有时间看规格,但它就在那里。 OP 代码必须比此处显示的更复杂。
  • @JamesThorpe “与setTimeout 一起排队的事情也会按顺序触发。” 不确定在document DOMContentLoaded 事件触发后是否是这种情况。如果documentwindow 尚未加载,相信队列是适用的。另见第 3045-3053 行
  • 但是事件不能在 OPs 代码期间触发。对ready 进行了 3 次简单的调用,中间不会发生任何其他事情。文档要么准备好,要么还没有。无论哪种方式,所有 3 个回调都将被添加到队列中并按顺序执行。如果 OP 真的看到了这种行为,那么他们已经过度简化了代码,并且隐藏了真正的原因。
  • @JamesThorpe plnk plnkr.co/edit/C0leBhYJq8CMh7WqndzH?p=preview 演示了 OP 描述的行为。只有第一个 .ready() 调用似乎将要调用的函数放入队列中。在completed 被调用的函数之后.ready() 似乎在setTimeout 内被调用
  • 嗯,这很好奇......如果您删除 window.document 并且只对第一个使用与其他两个相同的语法,问题就会消失。考虑到它们应该做同样的事情,这似乎是 jQuery 中不同样式的处理程序之间的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多