2011-09-20 13 views
71

Ho un problema in cui la pagina si sta caricando così velocemente, che jquery non ha finito il caricamento prima di essere chiamato da uno script successivo. C'è un modo per verificare l'esistenza di jQuery e se non esiste, attendere un momento e poi riprovare?Come eseguire l'esecuzione dello script attendere il caricamento di jquery


In risposta alle risposte/commenti di seguito, inserisco parte del markup.

La situazione ... pagina master e pagina di asp.net.

Nella pagina master, ho un riferimento a jquery. Quindi nella pagina di contenuto, ho un riferimento allo script specifico della pagina. Quando viene caricato lo script specifico della pagina, si lamenta che "$ non è definito".

ho messo avvisi in diversi punti nel markup per vedere l'ordine in cui le cose stavano sparando, e ha confermato che si spara in questo ordine: intestazione di pagina

  1. Maestro.
  2. Blocco contenuto pagina figlio 1 (situato all'interno della testina della pagina principale, ma dopo che gli script della pagina principale sono chiamati).
  3. Bambino blocco contenuto della pagina 2.

Ecco il markup in cima masterpage:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="SiteMaster" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head id="Head1" runat="server"> 
    <title>Reporting Portal</title> 
    <link href="~/Styles/site.css" rel="stylesheet" type="text/css" /> 
    <link href="~/Styles/red/red.css" rel="stylesheet" type="text/css" /> 
    <script type="text/Scripts" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> 
    <script type="text/Scripts" language="javascript" src="../Scripts/jquery.dropdownPlain.js"></script> 
    <script type="text/Scripts" language="javascript" src="../Scripts/facebox.js"></script> 
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> 
    <asp:ContentPlaceHolder ID="head" runat="server"> 
    </asp:ContentPlaceHolder> 
</head> 

Poi nel corpo del masterpage, v'è un ulteriore ContentPlaceHolder:

<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server"> 
       </asp:ContentPlaceHolder> 

Nella pagina figlio, sembra così:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Dashboard.aspx.cs" Inherits="Data.Dashboard" %> 
<%@ Register src="../userControls/ucDropdownMenu.ascx" tagname="ucDropdownMenu" tagprefix="uc1" %> 
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server"> 
    <link rel="stylesheet" type="text/css" href="../Styles/paserMap.css" /> 
</asp:Content> 
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server"> 
***CONTENT HERE*** 
    <script src="../Scripts/Dashboard.js" type="text/javascript"></script> 
</asp:Content> 

Ecco il contenuto del file "../Script/Dashboard.js":

$(document).ready(function() { 

    $('.tgl:first').show(); // Show the first div 

    //Description: East panel parent tab navigation 
    $('.tabNav label').click(function() { 
     $('.tabNav li').removeClass('active') 
     $(this).parent().addClass('active'); 

     var index = $(this).parent('li').index(); 
     var divToggle = $('.ui-layout-content').children('div.tgl'); 

     //hide all subToggle divs 
     divToggle.hide(); 
     divToggle.eq(index).show(); 
    }); 

}); 
+4

stai usando '$ (documento) .ready (funzione() {...});'? – rownage

+0

Se si stanno caricando script con semplici tag '

4

Usa:

$(document).ready(function() { 
    // put all your jQuery goodness in here. 
}); 

Partenza questo per ulteriori informazioni: http://www.learningjquery.com/2006/09/introducing-document-ready

Nota: questo dovrebbe funzionare finché l'importazione di script per la libreria JQuery è al di sopra di questa chiamata.

Aggiornamento:

Se per qualche motivo il codice non sta caricando in modo sincrono (che non ho mai incontrato, ma a quanto pare può essere possibile dal commento qui sotto non dovrebbe succedere), è possibile codificare esso come il seguente

function yourFunctionToRun(){ 
    //Your JQuery goodness here 
} 

function runYourFunctionWhenJQueryIsLoaded() { 
    if (window.$){ 
     //possibly some other JQuery checks to make sure that everything is loaded here 

     yourFunctionToRun(); 
    } else { 
     setTimeout(runYourFunctionWhenJQueryIsLoaded, 50); 
    } 
} 

runYourFunctionWhenJQueryIsLoaded(); 
+5

questa attesa è finita la dom è pronta, non fino a quando jquery è caricato. probabilmente ha 2 file di script, 1 da un CDN (jquery da google e un plug-in localmente) dove 1 è caricato prima dell'altro .. .. il tuo codice non risolve questo, se il plugin viene caricato più velocemente di jquery stesso – Sander

+1

non sono d'accordo con te @Sander questo dovrebbe funzionare come il caricamento è sincrono – malko

+0

hai ragione, la mia ipotesi sul fatto che vengano caricati in modo asincrono se provengono da un dominio diverso è completamente sbagliata! scusami per questo – Sander

2

Non penso che sia il tuo problema. Il caricamento degli script è sincrono per impostazione predefinita, quindi, a meno che non si utilizzi l'attributo defer o si carichi jQuery tramite un'altra richiesta AJAX, il problema è probabilmente qualcosa di più simile a un 404. Puoi mostrare il tuo markup e farci sapere se vedi qualcosa di sospetto in firebug o web inspector?

15

è possibile utilizzare l'attributo rinviare per caricare lo script al davvero finire.

<script type='text/javascript' src='myscript.js' defer='defer'></script> 

ma normalmente si carica lo script nel corretto ordine dovrebbe fare il trucco, in modo da essere sicuri di mettere jquery all'inclusione prima il proprio script

Se il codice è nella pagina e non in un file js separato in modo devi eseguire lo script solo dopo che il documento è pronto e incapsulare il codice come questo dovrebbe funzionare anche:

$(function(){ 
//here goes your code 
}); 
+0

+1 per menzionare l'ordine di riferimento dello script. – Jack

+0

Questo va bene finché hai una singola dipendenza –

146

in ritardo alla festa, e simile alla domanda di Briguy37, ma per riferimento futuro io uso il seguente metodo e passare le funzioni I w formica di rinviare fino jQuery è caricato:

function defer(method) { 
    if (window.jQuery) { 
     method(); 
    } else { 
     setTimeout(function() { defer(method) }, 50); 
    } 
} 

Sarà ricorsivamente chiamare il metodo rinviare ogni 50ms fino window.jQuery esiste momento in cui esce e chiede method()

Un esempio con una funzione anonima:

defer(function() { 
    alert("jQuery is now loaded"); 
}); 
+4

Ricorda che $ potrebbe non essere sempre jQuery, ad esempio, sulla piattaforma Magento in cui la finestra. $ = Prototipo per impostazione predefinita. È più sicuro testare per 'window.jQuery'. – 10basetom

+0

Grazie! Incorporato nella risposta. +1 – Darbio

+0

Questo non ha funzionato per me. All'interno del metodo, $ non è stato definito ... non so ancora perché. –

6

È un problema comune, immagina di utilizzare un motore di templating di PHP, così hai il tuo layout di base:

HEADER 
BODY ==> dynamic CONTENT/PAGE 
FOOTER 

E, naturalmente, si legge da qualche parte che è meglio caricare Javascript nella parte inferiore della pagina, in modo che il contenuto dinamico non sappia chi è jQuery (o $).

Inoltre si legge da qualche parte che è utile inserire inline piccoli, quindi immagina di aver bisogno di jQuery in una pagina, baboom, $ non è definito (.. ancora ^^).

mi piace la soluzione di Facebook fornisce

window.fbAsyncInit = function() { alert('FB is ready !'); } 

Così come programmatore pigro (dovrei dire un buon programmatore ^^), è possibile utilizzare un equivalente (all'interno della pagina):

window.jqReady = function() {} 

E aggiungere alla parte inferiore del layout, dopo jQuery includere

if (window.hasOwnProperty('jqReady')) $(function() {window.jqReady();}); 
+0

Grazie! Questo è esattamente il caso che sto affrontando. – KumZ

12

ancora un altro modo per fare questo, alt Il metodo di differimento di Darbio è più flessibile.

(function() { 
    var nTimer = setInterval(function() { 
    if (window.jQuery) { 
     // Do something with jQuery 
     clearInterval(nTimer); 
    } 
    }, 100); 
})(); 
9

Si può provare a caricare l'evento. Essa ha sollevato quando tutti gli script sono stati caricati:

window.onload = function() { 
    //jquery ready for use here 
} 

Ma tenere a mente, che si può ignorare altri script in cui window.onload utilizzando.

+0

funziona ma probabilmente vedrai un lampo di contenuto senza stile se il tuo jQuery cambia l'aspetto della pagina –

1

Controllare questo:

https://jsfiddle.net/neohunter/ey2pqt5z/

Si creerà un oggetto falso jQuery, che consente di utilizzare i metodi OnLoad jQuery, e saranno eseguiti non appena jQuery è caricato.

Non è perfetto.

// This have to be on <HEAD> preferibly inline 
 
var delayed_jquery = []; 
 
jQuery = function() { 
 
    if (typeof arguments[0] == "function") { 
 
    jQuery(document).ready(arguments[0]); 
 
    } else { 
 
    return { 
 
     ready: function(fn) { 
 
     console.log("registering function"); 
 
     delayed_jquery.push(fn); 
 
     } 
 
    } 
 
    } 
 
}; 
 
$ = jQuery; 
 
var waitForLoad = function() { 
 
    if (typeof jQuery.fn != "undefined") { 
 
    console.log("jquery loaded!!!"); 
 
    for (k in delayed_jquery) { 
 
     delayed_jquery[k](); 
 
    } 
 
    } else { 
 
    console.log("jquery not loaded.."); 
 
    window.setTimeout(waitForLoad, 500); 
 
    } 
 
}; 
 
window.setTimeout(waitForLoad, 500); 
 
// end 
 

 

 

 
// now lets use jQuery (the fake version) 
 
jQuery(document).ready(function() { 
 
    alert('Jquery now exists!'); 
 
}); 
 

 
jQuery(function() { 
 
    alert('Jquery now exists, this is using an alternative call'); 
 
}) 
 

 
// And lets load the real jquery after 3 seconds.. 
 
window.setTimeout(function() { 
 
    var newscript = document.createElement('script'); 
 
    newscript.type = 'text/javascript'; 
 
    newscript.async = true; 
 
    newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'; 
 
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(newscript); 
 
}, 3000);

+0

questa è una soluzione senza problemi per la registrazione di funzioni pronte per documenti grazie a – zanedev

3

Invece di "Wait" (che di solito è fatto usando setTimeout), si potrebbe anche usare la definizione dell'oggetto jQuery nella finestra stessa come un gancio per eseguire il codice che si basa su di essa. Ciò è ottenibile attraverso una definizione di proprietà, definita utilizzando Object.defineProperty.

(function(){ 
    var _jQuery; 
    Object.defineProperty(window, 'jQuery', { 
    get: function() { return _jQuery; }, 
    set: function($) { 
     _jQuery = $; 

     // put code or call to function that uses jQuery here 

    } 
    }); 
})(); 
+0

questo sarebbe vagamente utile se jQuery effettivamente definisse una proprietà finestra, ma non sembra? – Jim

+0

In realtà non imposta una proprietà, ma imposta 'window.jQuery' su un valore, definendo la variabile' jQuery' nell'ambito globale (ad esempio 'window').Questo attiverà la funzione setter della proprietà sull'oggetto finestra definito nel codice. –

+0

Questo non funziona se la proprietà jQuery viene definita prima dell'esecuzione di questo codice; cioè se il tuo jquery.js differito viene caricato prima che questo codice venga caricato. Una soluzione è quella di mettere il tuo jquery.js posticipato prima di '' anziché prima di '' – user36388

1

il modo più semplice e più sicuro è quello di utilizzare qualcosa di simile:

var waitForJQuery = setInterval(function() { 
    if (typeof $ != 'undefined') { 

     // place your code here. 

     clearInterval(waitForJQuery); 
    } 
}, 10); 
1

Io non sono super appassionato dei thingies intervallo. Quando voglio differire jquery, o qualsiasi cosa in realtà, di solito è qualcosa di simile.

Inizia con:

<html> 
<head> 
    <script>var $d=[];var $=(n)=>{$d.push(n)}</script> 
</head> 

Poi:

<body> 
    <div id="thediv"></div> 

    <script> 
    $(function(){ 
     $('#thediv').html('thecode'); 
    }); 
    </script> 

    <script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script> 

Poi, finalmente:

<script>for(var f in $d){$d[f]();}</script> 
</body> 
<html> 

O il meno capogiro versione:

<script>var def=[];function defer(n){def.push(n)}</script> 
<script> 
defer(function(){ 
    $('#thediv').html('thecode'); 
}); 
</script> 
<script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script> 
<script>for(var f in def){def[f]();}</script> 

E nel caso di async è possibile eseguire le funzioni push su jquery onload.

<script async onload="for(var f in def){def[f]();}" 
src="jquery.min.js" type="text/javascript"></script> 

alternativa:

function loadscript(src, callback){ 
    var script = document.createElement('script'); 
    script.src = src 
    script.async = true; 
    script.onload = callback; 
    document.body.appendChild(script); 
}; 
loadscript("jquery.min", function(){for(var f in def){def[f]();}}); 
0

ho trovato che la soluzione suggerita funziona solo mentre badando codice asincrono. Ecco la versione che funzionerebbe in entrambi i casi:

document.addEventListener('DOMContentLoaded', function load() { 
    if (!window.jQuery) return setTimeout(load, 50); 
    //your synchronous or asynchronous jQuery-related code 
}, false); 
Problemi correlati