Caricamento asincrono di jQuery


manny tuttofare

In questo articolo mostreremo una tecnica facile da usare per caricare in maniera asincrona jQuery e migliorare i tempi di caricamento delle pagine e la velocità percepita dall’utente. La prima parte dell’articolo è incentrata sui vantaggi del caricamento asincrono e come siamo arrivati alla tecnica che stiamo proponendo. Per chi è interessato solo ad una soluzione copia e incolla, può andare alla fine (TL;DR). 🙂 

jQuery è una libreria Javascript che ha come obiettivo di semplificare la programmazione client nei browser, permettendo allo sviluppatore di concentrarsi sulla funzionalità che sta implementando piuttosto che perdere tempo dietro ai deliri delle differenze dei DOM dei vari browser.

Il suo motto si riassume in una frase. Write Less, Do More. Scrivi di meno, fai di più.

E da sviluppatore non posso che benedire jQuery per questo. Questa libreria realizza quello che dovrebbe essere un linguaggio di programmazione su browser. Uno standard. Chiunque abbia programmato in javascript su pagina web sa bene quali problemi di compatibilità ci possano essere fra i DOM dei vari browser (ed anche nello loro versioni).Usando jQuery non ci si preoccupa più di questo aspetto, visto che è delegato agli sviluppatori della libreria.

Grazie a questo suo pregio, jQuery è diventata una delle librerie javascript più usate nel mondo.

Secondo questa ricerca di Built With è usata dal 20% dei siti del web e ben dal 66.6% dei 10 mila siti più importanti.

C’è però una parte di me che non ama jQuery. Il mio lato ottimizzatore. Una delle cose che mi piace di più nello sviluppo, che sia un sito, un’app, o un gestionale è fare in modo che non ci siano sprechi di risorse, perché questo a lungo andare nella vita del software può causare un aumento dei costi o una diminuzione dei risultati. E riuscire ad ottenere risultati migliori è eccitante. In particolar modo su web.

Il Javascript è una zavorra
Rallenta il rendering della pagina, soprattutto se siamo su mobile.

Non è un segreto che un sito che abbia tempi di risposta lenti, sia meno gradito agli utenti. Sono meno predisposti a navigarlo, a diventarne utenti abituali, a convertire. E jQuery purtroppo contribuisce a rallentare i siti. E questo rallentamento è tanto più evidente quanto ci spostiamo dai browser desktop e della nostre veloci ADSL, andando sui tablet e sugli smartphone con connessioni 3G.

Questo perché il javascript è un linguaggio interpretato, il che vuol dire che ogni singola riga di codice viene convertita in linguaggio macchina durante l’esecuzione. Ogni volta che viene eseguita. Meno potenza di calcolo abbiamo a disposizione, tanto più l’esecuzione è lenta.

Non sempre è così, in alcuni casi ci sono comportamenti diversi. Ad esempio V8, il motore javascript di Chrome, si comporta in maniera un po’ diversa.

V8 compiles and executes JavaScript source code.

Ovvero V8 fa una compilazione e non una interpretazione di javascript. Questo comporta migliori prestazioni, in generale, ma in ogni caso la compilazione è una operazione pesante e su mobile dove abbiamo meno potenza la differenza si sente.

L’ideale sarebbe fare a meno del javascript. Ma non è semplice, i clienti vogliono i siti fichi, 2.0 (qualsiasi cosa significhi nella loro testa), ci vogliono gli slider, le tendine, dobbiamo stupire con gli effetti speciali (anche se parafrasando una vecchia pubblicità, preferisco dire che noi siamo scienza non fantascienza). Ed in questo jQuery fa benissimo il suo lavoro, avendo permesso la proliferazione di migliaia di plugin per ogni necessità.

Però questo ha un costo.

jQuery pesa
Sono ben 91k da scaricare

Supponiamo vogliate unicamente fare un menù a tendina per la barra di navigazione del vostro sito. Un banalissimo menù a tendina che fatto a mano, scrivendo tutto il codice javascript necessario senza alcuna libreria, prenderebbe meno di un k di codice. Con jQuery si fa con poche righe di codice, ancora meno. Ma dovendosi portare dietro i 91k di jQuery 1.10.2 minimizzati.

Per questo io dico che l’altra faccia di jQuery è Write less, Download more.

Non voglio entrare nel merito jQuery si, jQuery no, non è il tema di questo post. Il dato di fatto è che jQuery è comodo, permette di avere codice più manutenibile, si può attingere a tonnellate di cose già fatte.

Voglio quindi mostrarvi un modo per utilizzarlo, senza farsi troppo male dal punto di vista delle performance. E la parola d’ordine è asincrono. Abbiamo prima bisogno di fare due piccole digressioni.

Il ciclo di vita di una pagina

Cosa succede quando un utente digita un indirizzo sul suo browser?

Ciclo di vita di una pagina

Il ciclo di vita di una pagina, dalla richiesta al suo caricamento nel browser (Fonte StartByZero).

Questa immagine è tratta da Ottimizzazione delle performance di Massimo Della Rovere e descrive il ciclo di vita di una pagina, dal momento in cui l’utente digita una URL nella barra degli indirizzi al momento in cui la pagina si carica completamente sul browser.

In ognuna di queste fasi, possiamo intervenire per rendere più efficiente l’utilizzo delle risorse e dare all’utente una maggiore velocità di caricamento percepita.

Percepita e magari non reale perché all’utente non importa nulla che voi riusciate a generare una pagina in 85 ms. A lui importa che l’informazione che cerca si carichi subito, in meno di un secondo, in modo che non si interrompa il flusso di pensiero.

Se poi voi finite di caricare le informazioni raggiungibili muovendo la barra di scorrimento, mentre inizia a leggere, avete migliorato la velocità che lui percepisce, senza in effetti aver tagliato la banda necessaria a scaricare tutte le risorse.

jQuery interviene nel blocco E dell’immagine. Nel momento in cui avendo scaricato le risorse, si inizia a comporre graficamente la pagina. E come tutti i javascript, anche jQuery ha una bruttissima abitudine.

Ovvero di essere sincrono.

Cosa significa sincrono?

pentola con acqua che bolle sul fuocoSignifica che certe operazioni devono essere eseguite in sequenza. Immaginate voi che vi cucinate un piatto di pasta (esempio da asceta italico). Dovete prendere una pentola dalla credenza, riempirla d’acqua, metterla sui fuochi, aprire il gas e accendere la fiamma.

Alcune operazioni possono essere eseguite fuori sequenza, in parallelo (asincrono), mentre ne fate altre (ad esempio potete far aprire il gas ed accendere la fiamma ad un’altra persona, mentre voi prendete la pentola e la riempite d’acqua).

Mentre altre devono essere per forza eseguite nella sequenza prevista. Non potete riempire d’acqua, se prima non avete preso la pentola, e non potete accendere la fiamma se prima non avete aperto il gas.

Il javascript si esegue in maniera sincrona. Leggete cosa ci dice Google in proposito:

Before a browser can render a page to the user, it has to parse the page. If it encounters a blocking external script during parsing, it has to stop and download that Javascript. Each time it does that, it is adding a network round trip, which will delay the time to first render of the page.

Tratto da Remove Render-Blocking Javascript. Che significa che prima che il browser possa renderizzare la pagina, deve prima processare l’html. Se incontra un javascript, deve bloccare l’elaborazione dell’html, e scaricare il javascript. Ogni volta aggiunge un RTT (tempo necessario perché una richiesta abbia una risposta), che ritarda il momento di primo render della pagina.

Inoltre

However, more importantly for round-trip times, many browsers block the downloading of resources referenced in the document after scripts until those scripts are downloaded and executed

Tratto Minimize round-trip times. Che significa che molti browser bloccano lo scaricamento di una risorsa richiamata dopo un tag script, fintanto questo non è scaricato ed eseguito.

Quante cose brutte con l’uso sincrono del javascript.

Ma in pratica quanto penalizza l’utilizzo di jQuery?

Uno studio di Microsoft sul portale MSN, Performance Measurement and Case Studies at MSN ci dice (nel powerpoint scaricabile dall’indirizzo, alla diapositiva 18) che jQuery ritarda il primo render della pagina di 200/300 millisecondi e ritarda onload della pagina di 250 millisecondi.

In più scopriamo che hanno misurato, rendendo asincrono jquery, un incremento delle ricerche, e dei pageclick dello 0.5%. Non male.

Però non dimenticate qui stiamo parlando del solo jQuery. Nel tipico sito, soprattutto se c’è uno dei più diffusi cms, generalmente ci sono tanti altri script dipendenti, uno per i vari effetti che vengono usati. E quindi aggiungendo script sincrono su script sincrono, l’allungamento dei tempi del primo rendering aumenta. E si può arrivare tranquillamente ai secondi. Penso a questo punto di aver convinto buona parte di voi sulla necessità di essere asincroni.

Eureka, facciamo diventare tutto asincrono.

Essere asincroni non è facile

Si ma non facciamoci subito gasare troppo. La sincronia è l’abbraccio della mamma, dolce, tenero, facile e sicuro. Per l’asincronia si diventa grandi, bisogna imparare a coordinare le varie risorse di una pagina, per evitare di versare l’acqua prima di aver preso la pentola.

Aggiungiamo anche che jQuery non è stato (ancora) pensato per un caricamento asincrono in maniera nativa, come può accadere, ad esempio, per gli script di google maps o di analytics. Questo significa che caricare jQuery in maniera asincrona non è una cosa facile. Perché generalmente abbiamo degli script dipendenti. I vari plugin jQuery che possiamo aver inserito nella pagina.

Cosa succede se si scarica prima un plugin di jQuery, oppure se si scarica prima un plugin che necessita che ne sia stato scaricato un’altro prima. Quello di cui abbiamo bisogno è un sistema per far in modo di non usare qualcosa prima che tutte le sue propedeuticità siano state scaricate.

Nelle pagine di questo seo blog c’è una tecnica che è stata usata per rendere asincrono jquery. È molto efficiente, però non è facile da implementare sopratutto su pagine composte per componenti, è più difficile da manutenere e non permette di sfruttare il caricamento parallelo di più script. E nel caso volessimo rendere asincrono un sito già esistente, ci sono un discreto numero di modifiche da fare.

Per questo, per i miei progetti, ho cercato una tecnica alternativa. Tanto una tecnica è facile da implementare, tanto più frequentemente la posso usare. Non potrei mai usare tecniche che mi portano via ore o giorni di lavoro su progetti a basso budget (e alle volte anche su sito da medio-alto budget).

jQl

Prima di mettermi a sviluppare qualcosa da solo, come fanno tutti, ho aperto Google, e mi sono documentato se qualcuno potesse aver già affrontato il problema, e magari averlo risolto in maniera migliore di quello che potrei fare io. Ed ho trovato una soluzione molto elegante in jQl. Un loader per il caricamento asincrono di jQuery pensato sui seguenti principi

  • possibilità di caricare jQuery quanto prima possibile, senza dover mettere il codice a fondo pagina
  • caricamento non bloccante e parallelo di jQuery e di ogni plugin
  • possibilità di inserire script inline nella pagina all’interno del $(document).ready anche se jQuery e i suoi plugin ancora non sono stati caricati

Il codice può essere scaricato da Github ed è facilissimo da usare. Si tratta di soli 700 byte minimizzati e gzipped e vanno inseriti inline all’interno dell’html, prima di qualsiasi altro codice.

N.B.: per brevità negli esempi che seguono non ho inserito la classe che definisce jQl. La troverete solo nell’esempio finale e nella demo a fine articolo.

Supponete di avere il seguente codice nella vostra pagina

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">
</script>
<script type="text/javascript">
$('document').ready(function(){
    alert('Ciao mondo');
    });
</script>

Questo codice non fa altro che mandare un alert con la scritta Ciao mondo, al momento dell’evento ready della pagina. Se volessi renderlo asincrono, diventerebbe così:

<script type="text/javascript">
// qui va inserito una volta per pagina il codice minimizzato di jQL
jQl.loadjQ('https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js');
$('document').ready(function(){
   alert('Ciao mondo');
   });
</script>

A prima vista questo codice dovrebbe andare in errore.

Non essendo ancora stato caricato jQuery, ancora non è stato definito $. Ricordate che adesso siamo asincroni. Quando arriviamo al $(‘document’).ready(function(){ è appena stato lanciato il caricamento della libreria. Se fossimo sincroni, il parsing della pagina sarebbe sospeso fino al completamento del caricamento di jQuery. Ora non è più così.

E allora come fa a funzionare? A mio avviso è qui l’eleganza di questa soluzione. Il loader, rimappa le varie forme in cui può essere scritto il  $(‘document’).ready, e quindi al momento in cui va in esecuzione, non viene effettivamente eseguito il codice all’interno dell’evento, ma viene accodato in un array per essere eseguito al momento del caricamento di jQuery. jQl non permette solo il caricamento asincrono di jQuery, ma anche di qualsiasi plugin di cui possiamo aver bisogno in pagina. Ed anche questo molto semplice.

<script type="text/javascript">
// qui va inserito una volta per pagina il codice minimizzato di jQl
jQl.loadjQ('https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js');
jQl.loadjQdep('js/myplugin.jquery.js');
$('document').ready(function(){
    alert('Ciao mondo');
    });
</script>

Quindi in pratica, basta sostituire il tag script che chiama jQuery con un jQl.loadjQ ed ogni tag script che richiama un plugin con un jQl.loadjQdep, senza necessità di altre modifiche. Poi ci pensa jQl a far eseguire il codice all’interno dei $(‘document’).ready quando ha scaricato tutto. jQl ha anche qualche altra opzione, che potete vedere sull’articolo originale. Il modo in cui lo uso io è quello che vi ho descritto. L’uso è semplicissimo. Vediamo quali sono le limitazioni ed i casi di utilizzo.

  • jQl.loadjQ deve essere usato solo per caricare jQuery che può essere hostato in locale oppure da una qualsiasi cdn come negli esempi.
  • jQl.loadjQdep può caricare qualsiasi plugin, però devono risiedere nello stesso host in cui si trova la pagina. Questo è dovuto alla tecnica usata per scaricare il codice. Quindi un eventuale jQueryUI deve risiedere in locale e non può essere scaricata da una cdn.
  • il codice inline che usa jQuery deve risiedere tutto dentro a $(‘document’).ready (eventualmente inserito anche più volte nel codice)
  • i plugin usati non devono usare $(window).load (il motivo lo spiegherò più avanti)

Dopo aver trovato la soluzione al mio problema, ovviamente ho iniziato qualche test. Prima in locale su qualche progettino semplice, e dopo il responso positivo l’ho provato on line. E qui ho trovato qualche problema.

Nel senso che alcune volte non veniva eseguito il mio codice nel $(‘document’).ready. Dopo qualche ricerca, ho trovato sul repository del progetto su GitHub, una segnalazione che corrispondeva al mio problema. Un utente ha rilevato che il codice proposto non riusciva sempre a rispettare l’ordine di scaricamento delle dipendenze e non faceva eseguire il codice inline aspettando che tutte fossero scaricate. Qui si può scaricare la sua proposta di modifiche al codice originario.

A questo punto ho effettuato un nuovo giro di verifiche. Andava decisamente meglio, ma ancora avevo dei problemi. Su un progetto dove le pagine contenevano molto HTML.

Dopo qualche ora di debug sono riuscito a capire la causa del problema. In alcuni casi jQl scaricava molto velocemente jQuery e le sue dipendenze e quindi eseguiva il codice nel $(‘document’).ready prima che tutto il DOM fosse caricato. In pratica eseguiva il codice nel ready, prima che la pagina fosse effettivamente ready.

Era necessaria quindi un’altra modifica che ho fatto io stesso. Dopo questa modifica, i miei test sono stati superati con successo. Ed ho iniziato a rilasciare il codice su diversi progetti in produzione. In effetti la modifica era molto semplice da applicare. Dopo un paio di settimane di verifiche senza alcuna anomalia, ho iniziato a fare qualche esperimento più ardito, per verificare se ci fossero ulteriori limitazioni.

Una delle cose che ho provato è stata di applicare una tecnica che di solito uso per caricare dopo l’evento onload le risorse di una pagina che sono meno importanti. E di solito il codice che effettua questo caricamento lo inserisco all’interno di un $(window).load. Dato che il loader prevede che tutto il codice inline sia all’interno di un $(‘document’).ready, allora ho usato questo tipo di dichiarazione

<script type="text/javascript">
$('document').ready(function(){
    $(window).load(function(){
        // mio codice da eseguire al load
    });
});
</script>

In questo modo ho definito il gestore dell’evento load nel momento in cui il DOM è ready.

E sono tornato a testare. Inaspettatamente, provando il codice online ho rilevato che alcune volte il gestore dell’onload non veniva lanciato. Alcune volte sì, alcune volte no.

Il mio primo pensiero è stato che per qualche motivo ci fosse qualche risorsa che rimanesse appesa. In tal caso l’onload non viene lanciato perché effettivamente la pagina non ha terminato il caricamento.

Ma mi sbagliavo. Stavo pensando in maniera sincrona. Erroneamente.

Programmando in maniera sincrona gli eventi sono sempre lanciati nell’ordine in cui uno si aspetta. Prima il ready e poi il load. Nei casi in cui avevo un errato funzionamento, i miei eventi venivano lanciati effettivamente al contrario. Sembrerebbe un assurdo ma non è così.

Nel momento in cui la pagina viene scaricata jQl inizia lo scaricamento ASINCRONO di jQuery e dei plugin dipendenti, e secondo il suo funzionamento mette in un array il codice all’interno del $(‘document’).ready per mandarlo in esecuzione nel momento che jQL abbia fatto il suo lavoro.

Quello che può succedere è che questo codice, il gestore del mio ready, venga eseguito dopo il ready del DOM e dopo l’onload.

Quindi al momento del mio ready, io sto provando ad assegnare il gestore all’onload, che però non verrà mai eseguito perché effettivamente l’onload è già stato già lanciato.

Ragionando in asincrono non ho la certezza di quale sia la sequenza con cui vengono lanciati gli eventi, e può variare nella stessa pagina a seconda del caching, dei tempi di caricamento dei file, in modo che non possa essere previsto a priori. Questo è il motivo per cui i plugin che usano il $(window).load possono avere dei problemi, perché nel loro sviluppo non è previsto che l’onload possa avvenire prima del ready.

Dato che a me personalmente può fare comodo usare questo evento, ho deciso di fare un’ulteriore modifica a jQl, introducendo una proprietà pageIsLoaded per sapere se l’evento onload sia già stato lanciato o meno. Quindi il codice per dichiarare l’onload diventa

<script type="text/javascript">
$('document').ready(function(){
    if (jQl.pageIsLoaded){
        // mio codice da eseguire al load
    }
    else
        $(window).load(function(){
            // mio codice da eseguire al load
        });
});
</script>

In pratica verifico se l’onload è già stato lanciato. Se sì eseguo immediatamente il codice da eseguire al load, altrimenti assegno un gestore con lo stesso codice per quando scatterà l’onload. In questo modo siamo arrivati finalmente alla versione definitiva del loader, che ci permette di gestire un’ampia casistica.

Il codice definitivo lo potete scaricare da qui. Sono conscio del fatto di essere stato abbastanza lungo, ci sono volute quasi tre mila parole per farvi arrivare al codice definitivo (ricordate che va messo inline in pagina) :-), però trovavo interessante raccontare il percorso che mi ha permesso di arrivare qui.

Per aiutarvi a capire che genere di problemi possono capire usando una gestione asincrona. E come trovare una soluzione.

Conoscendo bene questa tematica, quando vi capiterà, potrete dire “Questo è curioso” ed usare la problematica come spunto per una nuova soluzione.

sincrono vs asincrono
non c'è storia.

A questo punto ci rimane solo da fare una prova su strada del nostro nuovo loader. Abbiamo creato due pagine, una con il caricamento di jQuery e plugin in maniera sincrona ed una con il caricamento di queste risorse in maniera asincrona. Vediamo quali sono le loro prestazioni.

In entrambe le pagine abbiamo gli stessi elementi. Una pagina in html senza alcun server side, con il caricamento di jquery e due plugin. Un classico lightbox per la visualizzazione di immagini ed un alert grafico. Inoltre è presente anche una mappa realizzata tramite le google maps api.

La google map è una difficoltà in più. Come avevo scritto sopra, jQl può caricare solo jquery da server esterni, e l’api di Google Maps si carica obbligatoriamente dai server di Google. In casi come questo non è possibile usare jQuery, ma si deve adottare una soluziona caso per caso.

In questo caso sono stato fortunato, in quanto le google maps api hanno una modalità di caricamento asincrono. Che ho abilitato dall’interno di un $(‘document’).ready. Questo significa che se abbiamo a che fare con api esterne, non abbiamo la certezza a priori di riuscire a renderle asincrone. Potete guardare il sorgente della pagina per vedere la soluzione adottata.

Per verificare la differenza nei tempi di caricamento, ho usato Speedoo. Qui potete vedere i risultati dettagliati per la pagina con il caricamento sincrono e qui quelli della pagina con caricamento asincrono.

Come è possibile vedere dai numeri, abbiamo sensibili miglioramenti sia nei tempi del primo rendering, che nei tempi di caricamento del DOM. Addirittura per quest’ultimo abbiamo un dimezzamento dei tempi dei caricamento sul primo accesso alla pagina.

Però tralasciamo i numeri. A chi visita il vostro visto non importa nulla dei numeri o a gare con il righello fra sviluppatori. La cosa più importante è che all’occhio del visitatore la pagina con il caricamento asincrono è decisamente più veloce a comporsi. Quello che abbiamo fatto è stato semplicemente cambiare il modo in cui vengono caricati gli elementi. In entrambe le pagine vengono caricate le stesse identiche cose, il peso è lo stesso, non abbiamo risparmiato un byte (anzi ne abbiamo usato qualcuno di più per jQl). È solo il caricamento ad essere più furbo. Ora il javascript non blocca il rendering della pagina o lo scaricamento di altre risorse.

Riassumendo per chi non si è voluto leggere le tremila parole precedenti, e vuole la soluzione copia e incolla per usare jQl e caricare jQuery in maniera asincrona, quello che deve inserire in pagina è:

<script type="text/javascript">
var jQl={q:[],dq:[],dMap:[],dLoaded:0,gs:[],ready:function(e){if(typeof e=="function"){jQl.q.push(e)}return jQl},getScript:function(e,t){jQl.gs.push([e,t])},unq:function(){for(var e=0;e<jQl.q.length;e++)jQl.q[e]();jQl.q=[]},ungs:function(){for(var e=0;e<jQl.gs.length;e++)jQuery.getScript(jQl.gs[e][0],jQl.gs[e][1]);jQl.gs=[]},bId:null,boot:function(e){if(typeof window.jQuery.fn=="undefined"){if(!jQl.bId){jQl.bId=setInterval(function(){jQl.boot(e)},25)}return}if(!window.jQuery.isReady){return;}if(jQl.bId){clearInterval(jQl.bId)}jQl.bId=0;jQl.testFinished();jQl.ungs();jQuery(jQl.unq());if(typeof e=="function")e()},booted:function(){return jQl.bId===0},testFinished:function(){if(typeof window.jQuery.fn=="undefined"){setTimeout(jQl.testFinished,10);return}if(jQl.dLoaded!=jQl.dMap.length){setTimeout(jQl.testFinished,10);return}jQl.unqjQdep(true);$(jQl.unq())},loadjQ:function(e,t){setTimeout(function(){var t=document.createElement("script");t.src=e;document.getElementsByTagName("head")[0].appendChild(t)},1);jQl.boot(t)},loadjQdep:function(e){jQl.dMap.push(e);jQl.loadxhr(e,jQl.qdep);jQl.dCount++},qdep:function(e,t){if(e){jQl.dLoaded++;jQl.dq[t]=e}},unqjQdep:function(e){if(typeof e!="undefined"&&typeof window.jQuery.fn=="undefined"){setTimeout(jQl.unqjQdep,50);return}for(var t=0;t<jQl.dMap.length;t++)jQl.rs(jQl.dq[jQl.dMap[t]]);jQl.dq=[];jQl.dMap=[]},rs:function(e,t){var n=document.createElement("script");document.getElementsByTagName("head")[0].appendChild(n);n.text=e},loadxhr:function(e,t){var n;n=jQl.getxo();n.onreadystatechange=function(){if(n.readyState!=4||200!=n.status)return;t(n.responseText,e)};try{n.open("GET",e,true);n.send("")}catch(r){}},getxo:function(){var e=false;try{e=new XMLHttpRequest}catch(t){var n=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];for(var r=0;r<n.length;++r){try{e=new ActiveXObject(n[r])}catch(t){continue}break}}finally{return e}},pageIsLoaded:false,setIsLoaded:function(){jQl.pageIsLoaded=true;}};if(typeof window.jQuery=="undefined"){var $=jQl.ready,jQuery=$;$.getScript=jQl.getScript};if (window.attachEvent){window.attachEvent('onload',jQl.setIsLoaded);}else if(window.addEventListener){window.addEventListener('load',jQl.setIsLoaded,false);}else{document.addEventListener('load',jQl.setIsLoaded,false);}

jQl.loadjQ('//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js');
jQl.loadjQdep('js/myplugin.jquery.js');
$('document').ready(function(){
    alert('Ciao mondo');
    });
</script>

Spero che questo codice vi sia utile nei vostri progetti. Happy coding.

La frase più eccitante della scienza, quella che si fa araldo di nuove scoperte, non è ‘Eureka‘ ma ‘Questo è curioso!’ (Isaac Asimov)

Immagine della pentola da https://bit.ly/19o4XWM
Immagine di Manny da https://bit.ly/19o56JN

Scritto il

Sei membro del forum? Vuoi scrivere anche tu su SEO Blog gt
Chiedilo a @giorgiotave