2009-03-27 3 views
48

У меня есть страница, которая динамически добавляет ссылки на сценарии через функцию $.getScript jQuery. Сценарии загружаются и выполняются отлично, поэтому я знаю, что ссылки верны. Однако, когда я добавляю оператор «отладчик» к любому из скриптов, чтобы позволить мне выполнить код в отладчике (например, VS.Net, Firebug и т. Д.), Он не работает. Похоже, что что-то о том, как загружает сценарии jQuery, мешает отладчикам находить файлы.Сценарии отладки, добавленные функцией jQuery getScript

У кого-нибудь есть обход для этого?

+0

Для тех, кто приезжают сюда из Google, принятый ответ на этот вопрос помог мне отладки динамически загружаемых скриптов в Chrome: https://stackoverflow.com/questions/9092125/how-to-debug-dynamically-loaded- javascriptwith-jquery-in-the-browsers-debugge –

ответ

73

Итак, оказывается, что реализация по умолчанию функции $.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 Debugger).

Обходным путем является переопределение функции $.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> 
+1

приятно. Испытывали ли вы какие-либо проблемы, о которых я должен знать, поскольку вы отправили этот ответ? ;) –

+0

Я не думаю, что этот метод использует глобальные события ajax. Не уверен. –

+1

, может быть, в точку крекинта, я попробовал это, и он не работал для сценария, который мне нужен. Я выкопался и заметил, что сценарий, который я хотел отлаживать, получал с помощью $ .ajax() вместо $ .getScript(). я просто изменил его, чтобы использовать $ .getScript() все было круто. – the0ther

2

Попробуйте это,

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; 

} 
    }); 
17

С 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); 
      } 
     }) 
+1

Ницца. Я устанавливаю crossDomain в options.development (bool), поэтому при разработке я могу отлаживать, иначе я могу его игнорировать. – Kriem

+2

Я пробовал это, и это, похоже, сработало. Я могу увидеть источник JS в отладчике, и я могу установить точку останова. Но есть одна проблема: каждый раз, когда я иду туда и обратно, новый JS-файл загружается с новым ID # (script.js? _ = 2345678) и т. Д. Любое обходное решение для этого? –

+0

@SamikR Установите 'cache: false', поэтому он не добавит это случайное число в конец имени файла –

13

Для тех, кто хотел бы отлаживать скрипты и использовать их с $ .when (ответ Джеймса Мессингер в не очень хорошо работает с $ .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(); 
}; 

Все кредиты и слава идут к Бенджамину Думке-фон-дер-Эхе и его статье: jQuery script insertion and its consequences for debugging

Это хорошо работает с $ .when, и скрипт полностью виден и отлаживается. Спасибо.

+0

Nice! Прямо из источника [jquery] (https://github.com/jquery/jquery/blob/1.11.0/src/ajax/script.js) с незначительными изменениями, которые сценарий не удаляется из DOM. – styfle

+1

Awesome. Кроме того, похоже, что $ .getScript предотвратит кэширование для меня. Переключение на ваше решение также исправлено, что должно ускорить процесс для наших клиентов! –

0

Есть простой способ отладить его с помощью Chrome.

1- Напишите console.log («что-то») в строке, которую вы хотите отлаживать.

2- Следите за консолью для этого журнала.

sample log

3- Нажмите на ссылку адреса в передней части бревна.

4- Установить точку останова на этой линии.

+1

вы можете использовать ключевое слово 'debugger;' в строке, где вы хотите отладить код. –

0

Чтобы избежать большого количества дополнительного кодирования, вы можете попробовать это. В файле, где вы объявили свой $ («документ»). Готов() (или любой другой файл, ваш отладчик будет доступ), добавить что-то вроде ...

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

Добавить контрольную точку в линии назначения в вашем отладчике. Тогда в любой другой JS-файл загружается с $ .getScript(), вы можете добавить ...

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

Всякий раз, когда эта строка выполняется ваш отладчик остановится и ждать вашей команды. Выйдите из функции $ .debug и все!

0

В Firefox 38.6.0 с Firebug 2.0.14, когда я перехожу на вкладку «Сценарий», я вижу запись в выпадающем меню, например jquery-1.11.1.js line 338 > eval и содержит загруженный скрипт. Кроме того, глядя на код в этой версии JQuery, это выглядит как внутренне $.getScript() использует $.get() и в конечном счете $.ajax(), единственным отличием является eval() часть для сценария, который обрабатывается с помощью функции JQuery globalEval():

// 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); 
    } 
}, 
0

Это сочетает решение OP с решением Эрика. Переопределите необходимый jquery, чтобы лечить, как всегда, crossdomain, и они отлично появятся, не нарушив ни одной вещи в реализации обещания jquery.

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 
}); 
} 


});