【问题标题】:Debugging scripts added via jQuery getScript function通过 jQuery getScript 函数添加的调试脚本
【发布时间】:2010-10-16 00:03:11
【问题描述】:

我有一个通过 jQuery 的 $.getScript 函数动态添加脚本引用的页面。脚本加载并执行良好,所以我知道引用是正确的。但是,当我向任何脚本添加“调试器”语句以允许我在调试器(例如 VS.Net、Firebug 等)中单步执行代码时,它不起作用。似乎 jQuery 加载脚本的方式阻止了调试器找到文件。

有人可以解决这个问题吗?

【问题讨论】:

标签: javascript jquery visual-studio debugging


【解决方案1】:

好的,事实证明$.getScript() 函数的默认实现会根据引用的脚本文件是否在同一个域中而有所不同。外部参考,例如:

$.getScript("http://www.someothersite.com/script.js")

会导致jQuery创建一个外部脚本引用,可以毫无问题地调试。

<script type="text/javascript" src="http://www.someothersite.com/script.js"></script>

但是,如果您引用本地脚本文件,例如以下任何内容:

$.getScript("http://www.mysite.com/script.js")
$.getScript("script.js")
$.getScript("/Scripts/script.js");

然后jQuery将异步下载脚本内容,然后将其添加为内联内容:

<script type="text/javascript">{your script here}</script>

后一种方法适用于我测试过的任何调试器(Visual Studio.net、Firebug、IE8 调试器)。

解决方法是覆盖$.getScript() 函数,以便它始终创建外部引用而不是内联内容。这是执行此操作的脚本。我已经在 Firefox、Opera、Safari 和 IE 8 中对此进行了测试。

<script type="text/javascript">
// Replace the normal jQuery getScript function with one that supports
// debugging and which references the script files as external resources
// rather than inline.
jQuery.extend({
   getScript: function(url, callback) {
      var head = document.getElementsByTagName("head")[0];
      var script = document.createElement("script");
      script.src = url;

      // Handle Script loading
      {
         var done = false;

         // Attach handlers for all browsers
         script.onload = script.onreadystatechange = function(){
            if ( !done && (!this.readyState ||
                  this.readyState == "loaded" || this.readyState == "complete") ) {
               done = true;
               if (callback)
                  callback();

               // Handle memory leak in IE
               script.onload = script.onreadystatechange = null;
            }
         };
      }

      head.appendChild(script);

      // We handle everything using the script element injection
      return undefined;
   },
});
</script>

【讨论】:

  • 不错。自从您发布此答案以来,您是否遇到过任何我应该注意的问题? ;)
  • 我不认为这种方法利用了全局 ajax 事件.. 不确定。
  • 也许是 shrikant 的观点,我试过了,但它不适用于我想要的脚本。我仔细研究了一下,发现我想调试的脚本是用 $.ajax() 而不是 $.getScript() 来调用的。我只是将其更改为使用 $.getScript() 一切都很酷。
  • 非常感谢您分享这个。这对我有很大帮助。
  • 此代码不适用于 $.when。有人知道如何解决吗?
【解决方案2】:

使用 JQuery 1.6(可能是 1.5),您可以切换到不使用 getScript,而是使用 jQuery.ajax()。然后设置 crossDomain:true 就会得到同样的效果。

错误回调将不起作用。所以你最好不要像下面这样设置。

但是,我确实设置了一个计时器并成功清除它。因此,如果我没有听到任何声音,那么在 10 秒后说,我认为文件是错误的。

        jQuery.ajax({
            crossDomain: true,
            dataType: "script",
            url: url,
            success: function(){
                _success(_slot)
            },
            error: function(){
                _fail(_slot);
            }
        })

【讨论】:

  • 不错的一个。我将 crossDomain 设置为 options.development (bool),所以在开发时我可以调试,否则我可以忽略它。
  • 我试过这个,这似乎有效。我确实可以在调试器中看到 JS 源代码,并且可以设置断点。但是有一个问题:每次来回时,都会下载一个带有新 ID # (script.js?_=2345678) 等的新 JS 文件。有什么解决方法吗?
  • @SamikR 设置cache: false 这样它就不会将该随机数添加到文件名的末尾
  • @ArashMilani 谢谢。我已经通过使用脚本的最后一个副本而不是通过 AJAX 加载它来解决它。只需检查以下内容: if(!window.MyScript){ AJAX }, else { // 调用加载函数。效果很好。
【解决方案3】:

对于那些想要调试脚本并将它们与 $.when 一起使用的人(James Messinger 的回答不适用于 $.when),我建议使用以下代码:

var loadScript = function (path) {
  var result = $.Deferred(),
  script = document.createElement("script");
  script.async = "async";
  script.type = "text/javascript";
  script.src = path;
  script.onload = script.onreadystatechange = function (_, isAbort) {
      if (!script.readyState || /loaded|complete/.test(script.readyState)) {
         if (isAbort)
             result.reject();
         else
            result.resolve();
    }
  };
  script.onerror = function () { result.reject(); };
  $("head")[0].appendChild(script);
  return result.promise();
};

所有功劳和荣耀归于 Benjamin Dumke-von der Ehe 和他的文章:jQuery script insertion and its consequences for debugging

这适用于 $.when 并且脚本是完全可见和可调试的。 谢谢。

【讨论】:

  • 不错!直接从jquery source 中删除,只是脚本没有从 DOM 中删除。
  • 太棒了。此外,似乎 $.getScript 会阻止我缓存。切换到您的解决方案也解决了这个问题 - 这应该会为我们的客户加快速度!
【解决方案4】:

试试这个,

jQuery.extend({
getScript: function(url, callback) {
    var head = document.getElementsByTagName("head")[0];

    var ext = url.replace(/.*\.(\w+)$/, "$1");

    if(ext == 'js'){
        var script = document.createElement("script");
        script.src = url;
        script.type = 'text/javascript';
    } else if(ext == 'css'){
        var script = document.createElement("link");
        script.href = url;
        script.type = 'text/css';
        script.rel = 'stylesheet';
    } else {
        console.log("Неизветсное расширение подгружаемого скрипта");
        return false;
    }



    // Handle Script loading
    {
        var done = false;

        // Attach handlers for all browsers
        script.onload = script.onreadystatechange = function(){
            if ( !done && (!this.readyState ||
            this.readyState == "loaded" || this.readyState == "complete") ) {
                done = true;
                if (callback)
                callback();

                // Handle memory leak in IE
                script.onload = script.onreadystatechange = null;
            }
        };
    }

    head.appendChild(script);

    // We handle everything using the script element injection
    return undefined;

} 
   });

【讨论】:

    【解决方案5】:

    有一种使用 Chrome 调试它的简单方法。

    1- 在要调试的行上写一个 console.log("something")。

    2- 观察该日志的控制台。

    3- 点击日志前面的地址链接。

    4- 在该行设置断点。

    【讨论】:

    • 你可以使用关键字'debugger;'在要调试代码的行中。
    【解决方案6】:

    所有答案都在这个页面的某个地方,但我想为未来的读者总结一下。

    检查(动态添加的)文件下载

    使用 Chrome,您可以在 XHR 选项卡上的网络面板下看到使用 $.getScript (http://api.jquery.com/jQuery.getScript/) 添加的 Javascript 文件;请注意,它们不会出现在 JS 选项卡下。

    调试文件

    1) 在代码中设置断点。正如在其他答案\cmets 中提到的,您可以插入一个

    debugger;
    

    Javascript 代码中的语句。这将调用浏览器的调试器。请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger 了解更多信息。

    2) 使用Source Map 使其出现在浏览器的Sources 面板中(在Chrome 中测试)。添加

    //# sourceURL=whatevername.js
    

    到文件的末尾。 [该文件出现在 Chrome 源代码面板中的 (no-domain) 下]。

    见: How to debug dynamically loaded JavaScript (with jQuery) in the browser's debugger itself?https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map 了解更多信息。

    3) 覆盖 $.getScript 以始终​​根据接受的答案使用外部引用(我尚未测试)。

    【讨论】:

      【解决方案7】:

      为了避免大量额外的编码,您可以试试这个。在您声明 $('document').ready()(或您的调试器将访问的任何其他文件)的文件中,添加类似...

      $.debug = function(name) {
         var n = name;
      }
      

      在调试器的赋值行中添加断点。然后,在您使用 $.getScript() 加载的任何其他 js 文件中,您可以添加 ...

      $.debug("some string to identify this point of code");
      

      每当执行此行时,您的调试器都会停止并等待您的命令。跳出 $.debug 函数就可以了!

      【讨论】:

        【解决方案8】:

        在带有 Firebug 2.0.14 的 Firefox 38.6.0 中,当我转到“脚本”选项卡时,我在下拉菜单中看到一个条目,例如 jquery-1.11.1.js line 338 &gt; eval,其中包含已加载的脚本。另外,查看这个版本的 jQuery 中的代码,看起来内部 $.getScript() 使用的是 $.get() 并最终使用 $.ajax(),唯一的区别是脚本的 eval() 部分,它由 jQuery @ 处理987654326@函数:

        // Evaluates a script in a global context
        // Workarounds based on findings by Jim Driscoll
        // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
        globalEval: function( data ) {
            if ( data && jQuery.trim( data ) ) {
                // We use execScript on Internet Explorer
                // We use an anonymous function so that context is window
                // rather than jQuery in Firefox
                ( window.execScript || function( data ) {
                    window[ "eval" ].call( window, data );
                } )( data );
            }
        },
        

        【讨论】:

          【解决方案9】:

          这将 OP 解决方案与 Eric 的解决方案相结合。覆盖必要的 jquery 以将 get 视为始终跨域,它们将完美显示而不会破坏 jquery promise 实现中的任何内容。

          jQuery.extend({
          get: function (url, data, callback, type) {
           // shift arguments if data argument was omitted
           if (jQuery.isFunction(data)) {
              type = type || callback;
              callback = data;
              data = undefined;
           }
          
           return jQuery.ajax({
              url: url,
              type: "GET":,
              dataType: type,
              data: data,
              success: callback,
              crossDomain: true
           });
          }
          
          
          });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-02-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多