archivi mensili: Gennaio 2014

Povero uomo di memorizzazione nella cache in JavaScript

[TL;Versione DR: utilizzare i cookie per memorizzare i risultati delle chiamate asincrone; rendere immediatamente i risultati delle precedenti chiamate asincrone e poi convalidarli dopo il caricamento della pagina.]

Sto lavorando sul sito intranet SharePoint per un cliente che caratterizza, tra le altre cose, una navigazione secondaria stilizzato cui opzioni di menu sono gestiti tramite un elenco personalizzato di vecchio regolare.  L'idea è che il cliente ottiene controllare il menu del "loro" sito senza influenzare o colpiti dalla navigazione globale messa da esso.

(c'è qualcosa di incredibilmente sovversiva sull'aggiunta di un CEWP che punta a un file HTML che carica alcuni CSS e JS per modificare sostanzialmente quasi tutto ciò che riguarda il comportamento di un sito... ma che è per un altro post)

Il codice per questo abbastanza semplice:

Qui il punto dolente è che ogni volta che qualcuno colpisce una delle pagine del sito, browser web dell'utente è protesa per ottenere elementi dall'elenco.  Una volta dev è completa e test ha dimostrato le cose per essere stabile e completa, Questa chiamata è inutile più di 99% del tempo poiché il menu cambia raramente.  Ha anche un effetto strano di UI che è comune in questo mondo nuovo iper-ajaxy siti web – il rendering della pagina e solo allora esegue il rendering dal menu.  È nervosa e fastidioso a mio parere.  E nervosa. Così, memorizzazione nella cache. 

Ho modificato la logica di questa convenzione:

  • Cercare un cookie nel browser che contiene il menu come ultima leggerla
    • Se trovato, rendere immediatamente.  Non aspettare che la pagina completare il caricamento.  (È necessario assicurarsi che il codice HTML è strategicamente collocato qui, ma non è difficile da fare).
  • Attendere la pagina di finire il caricamento e fare un async chiamare per caricare le voci di menu da un elenco utilizzando il resto o lists o qualunque
  • Confrontare quello che ho ottenuto con il cookie
    • Se corrisponde a, FERMATA
    • In caso contrario, usando jQuery, popolare dinamicamente un mazzo se <li>di in un <UL>
  • Utilizzare i CSS per fare la formattazione
  • Profitto!

Alcuni di voi stanno andando a dire, "Ehi! non non c'è nessun reale cache succedendo qui dato che stai leggendo il menu comunque ogni singola volta.”  E hai ragione-non sto dando il server qualsiasi tipo di pausa.  Ma perché la chiamata è async e accade dopo che la pagina iniziale di payload HTML rende pienamente, ci si "sente" più reattivo all'utente.  Il menu rende abbastanza tanto come disegna la pagina.  Se il menu succede al cambiamento, l'utente è soggetto a un ri-disegnare nervosa del menu, ma solo che una volta.

Ci sono alcuni modi per rendere più efficace questa memorizzazione nella cache e il server possono aiutare allo stesso tempo:

  • Mettere in una regola che il "cookie cache" è valida per un minimo di 24 ore o qualche altro lasso di tempo. Finchè non non c'è alcun cookie scaduti, utilizzare snapshot menu del cookie e mai colpito il server.

Beh... questo è tutto quello che mi vengono in mente ora :). 

Se qualcuno ha qualche idea intelligente qui mi piacerebbe conoscerli.

E infine – questa tecnica può essere utilizzata per altre cose.  Pagina su questo client ha un certo numero di cose basate su dati sulle varie pagine, molti di loro modifica relativamente raramente (come una volta a settimana o una volta al mese).  Se destinazione specifiche aree di funzionalità, si può dare un'interfaccia utente più reattiva tirando il contenuto dall'archivio locale cookie e rendendo immediatamente.  Ci si sente più velocemente all'utente anche se non si sta salvando il server qualsiasi cicli.  Si può salvare i cicli server decidendo su alcune condizioni e trigger per invalidare questa cache cookie locale.  Che è tutto situazionale e artsy roba e veramente la più divertente :). 

</fine>

undefinedIscriviti al mio blog.

Seguimi su Twitter a http://www.twitter.com/pagalvin

Come si fa: Configurare Unit Test e Test Coverage con QUnit.js e Blanket.js per un ufficio 365 SharePoint App

Intro

Hai esplorato unit test e test copertura per JavaScript come io lavoro su una nuova applicazione di SharePoint per SharePoint online in ufficio 365 Suite.  I percorsi di ricerca ovvio mi ha portato a Qunit.js e subito dopo che, A Blanket.js.

QUnit mi permetta di creare unit test e raggrupparli in moduli.  Un modulo è solo un semplice modo per organizzare i test correlati. (Non sono sicuro che sto usandolo come previsto, ma si sta lavorando per me finora con il piccolo insieme di test che finora ho definito).

Blanket.js integra con Qunit e mi mostrerà le linee effettive di JavaScript che sono stati – e ancora più importante – non sono stati effettivamente eseguite nel corso di esecuzione dei test.  Questa è la "copertura" – linee che eseguiti sono coperti dal test, mentre altri non sono.

Tra impostazione buone test case e visualizzazione di copertura, possiamo ridurre il rischio che il nostro codice ha nascosto i difetti.  Bei tempi.

Qunit

Assumendo che abbiate il vostro Visual Studio progetto impostato, inizia scaricando il pacchetto JavaScript da http://qunitjs.com.  Aggiungere JavaScript e CSS corrispondente alla soluzione.  Miniera assomiglia a questo:

image

Figura 1

Come si può vedere, Stavo usando 1.13.0 al momento ho scritto questo post del blog. Non dimenticate di scaricare e aggiungere il file CSS..

Che fuori del modo, il passo successivo è creare una sorta di prova imbrago e i bit Qunit di riferimento.  Sto testando un sacco di funzioni in un file di script chiamato "QuizUtil.js", così ho creato una pagina HTML denominata "QuizUtil_test.html" come mostrato:

image Figura 2

Ecco il codice:

<!DOCTYPE html>
<html xmlns= "http://www.w3.org/ 1999/xhtml">
<testa>
    <titolo>QuizUtil prova con Qunit</titolo>
    <link rel= "stylesheet" href="../CSS/qunit-1.13.0.CSS" />
    <script di tipo= text/javascript"" src="QuizUtil.js" dati-copertina></script di>
    <tipo di script ="text/javascript" src ="qunit-1.13.0.js"></script di>
    <tipo di script ="text/javascript" src ="blanket.min.js"></script di>

    <script di>
        modulo("getIDFromLookup");
        test("QuizUtil getIDFromLookupField", funzione () {
            var goodValue = 1";#Paul Galvin";

            uguale(getIDFromLookupField(goodValue) + 1, 2), "ID del [" + goodValue + "] + 1 dovrebbero essere 2";
            uguale(getIDFromLookupField(non definito), non definito, "Undefined argomento di input deve restituire un risultato indefinito.");
            uguale(getIDFromLookupField(""), non definito, "Argomento di input vuoto deve restituire un valore indefinito.");
            uguale(getIDFromLookupField("gobbledigood3-thq;dkvn ada;skfja sdjfbvubvqrubqer0873407t534piutheqw;VN"), non definito,"Deve sempre restituire un convertibile del risultato in un valore Integer");
            uguale(getIDFromLookupField(2";#qualche altra persona"), 2"", "Checking [2;#qualche altra persona].");
            uguale(getIDFromLookupField("9834524;#valore Long"), "9834524", "Prova di grande valore.");
            notEqual(getIDFromLookupField("5;#chiunque", 6), 6, "Prova un notEqual (5 non è uguale a 6 per questo esempio: [5;#chiunque]");

        });

        modulo("htmlEscape");
        test("QuizUtil htmlEscape()", funzione () {
            uguale(htmlEscape("<"), "&lt;", "Fuga a meno che l'operatore ('<')");
            uguale(htmlEscape("<classe div =  "someclass">Qualche testo</div>"), "&lt;div class =&quot;SomeClass&quot;&gt;Qualche testo&lt;/div&gt;", "Stringa di test più complesso.");
        });

        modulo("getDateAsCaml");
        test("QuizUtil getDateAsCaml()", funzione () {
            uguale(getDateAsCaml(Nuovo Data("31/12/2013")), "31T-12-2013:00:00:00", "Test data duramente codificato: [12/31/2013]");
            uguale(getDateAsCaml(Nuovo Data("01/05/2014")), "05T-01-2014:00:00:00", "Test data duramente codificato: [01/05/2014]");
            uguale(getDateAsCaml(Nuovo Data("01/31/2014")), "31T-01-2014:00:00:00", "Test data duramente codificato: [01/31/2014]");
            uguale(getTodayAsCaml(), getDateAsCaml(Nuovo Data()), "getTodayAsCaml() dovrebbe essere uguale getDateAsCaml(nuova data())");
            uguale(getDateAsCaml("valore di sciocchezze"), non definito, "Cercare di ottenere la data di un valore di sciocchezze.");
            uguale(getDateAsCaml(non definito), non definito, "Cercare di ottenere la data della [non definito] Data.");
        });

        modulo("getParameterByName");
        test("QuizUtil getParameterByName (dalla stringa di query)", funzione () {
            uguale(getParameterByName(non definito), non definito, "Cercare di ottenere indefinito parametro deve restituire indefinito.");
            uguale(getParameterByName("non esiste"), non definito, "Cercare di ottenere il valore del parametro quando sappiamo che il parametro non esiste.");

        });

        modulo("Cookies");
        test("QuizUtil varie funzioni di biscotto.", funzione () {
            uguale(setCookie("prova", 1"", -1), getCookieValue("prova"), "Get un cookie ho impostato dovrebbe funzionare.");
            uguale(setCookie("anycookie", 1"", -1), true, "L'impostazione di una cucina valida deve restituire 'vero'.");
            uguale(setCookie("nome del cookie pazzo !@#$%"%\^&*(()?/><.,", 1"", -1), true, "L'impostazione di un nome di cookie male deve restituire 'falsa'.");
            uguale(setCookie(non definito, 1"", -1), non definito, "Passing indefinito come il nome del cookie.");
            uguale(getCookieValue("non esiste"), "", "Cookie non esiste prova.");
        });

    </script di>
</testa>
<corpo>
    <div Identificazione= qunit""></div>
    <div Identificazione= "qunit-apparecchio"></div>

</corpo>
</html>

Ci sono parecchie cose che succedono qui:

  1. Il mio codice di riferimento (QuizUtil.js)
  2. Riferimento Qunity.js
  3. Definizione di alcuni moduli (getIDFromLookup, Cookies, e gli altri)
  4. Posizionando un <div> cui ID è "qunit".

Poi, Basta tirare su questa pagina e si ottiene qualcosa di simile:

image

Figura 3

Se guardi nella parte superiore, avete alcune opzioni, di cui due sono interessanti:

  • Nascondi superato test: Abbastanza evidente.  Può aiutare il vostro occhio vedere solo le aree di problema e non un sacco di confusione.
  • Modulo: (cadere giù): Questo consente di filtrare i test fino a solo quei gruppi di test che si desidera.

Per quanto riguarda i test stessi – alcune osservazioni:

  • Va da sé che è necessario scrivere codice, tale che in primo luogo è testabile.  Utilizzando lo strumento può aiutare a far rispettare tale disciplina. Per esempio, Ho avuto una funzione chiamata "getTodayAsCaml()”.  Questo non è verificabile molto poiché non prende nessun argomento di input e per verificare l'uguaglianza, dobbiamo costantemente aggiornare il codice di test per riflettere la data corrente.  Si rifattorizzato aggiungendo un parametro di input dati e passando la data corrente quando voglio la data odierna nel formato CAML.
  • Quadro Qunit documenta le proprie prove e sembra piuttosto robusto.  Possono fare cose semplici come test per l'uguaglianza e ha anche il supporto per le chiamate in stile ajax ("reale" o utilizzando il tuo preferito mocker deriso).
  • Passando attraverso il processo anche ti costringe a pensare attraverso casi limite – cosa succede con "undefined" o in una funzione viene passato null.  Lo rende morto semplice testare questi scenari fuori.  Roba buona.

Copertura con Blanket.js

Blanket.js completa Qunit l'effettive righe di codice che vengono eseguite durante il corso dell'esecuzione di test di rilevamento.  Esso integra diritto in Qunit anche se che è una app completamente separati, gioca bene – sembra davvero che è una app senza soluzione di continuità.

Questo è blanket.js in azione:

image Figura 4

image

Figura 5

(In realtà devi cliccare sulla casella di controllo "Attiva la copertura" nella parte superiore [Vedi figura 3] per consentire questo.)

Le righe evidenziate in figura 5 non sono stati eseguiti da alcuna delle mie prove, quindi ho bisogno di elaborare un test che causano loro di eseguire se voglio piena copertura.

Ottenere blanket.js lavorando seguendo questi passi:

  1. Scaricalo da http://blanketjs.org/.
  2. Aggiungerlo al progetto
  3. Aggiornare la tua pagina di prova imbrago (QuizUtil_test.html nel mio caso) come segue:
    1. Il codice di riferimento
    2. Decorare il vostro <script di> riferimento come questo:
    <script di tipo= text/javascript"" src="QuizUtil.js" dati-copertina></script di>

Blanket.js preleva l'attributo "dati-copertina" e fa la sua magia.  Aggancia Qunit, Aggiorna l'interfaccia utente per aggiungere l'opzione "Abilita la copertura" e voilà!

Riassunto (TL; DR)

Utilizzare Qunit per scrivere i test case.

  • Scaricarlo
  • Aggiungerlo al progetto
  • Scrivere una pagina di prova imbrago
  • Creare i test
    • Rifattorizzare alcuni del codice sia testabile
    • Essere creativi!  Pensare di crazy, scenari impossibili e li prova comunque.

Utilizzare blanket.js per garantire una copertura

  • Assicurarsi che il Qunit sta lavorando
  • Scarica blanket.js e aggiungerlo al progetto
  • Aggiungere alla tua pagina di prova imbrago:
    • Aggiungere un riferimento a blanket.js
    • Aggiungere un attributo "dati-copertura" al vostro <script di> Tag
  • Eseguire i test Qunit.

Non ho mai fatto nulla di tutto questo prima e aveva alcune cose rudimentali in una manciata di ore di lavoro. 

Test felice!

</fine>

undefinedIscriviti al mio blog.

Seguimi su Twitter a http://www.twitter.com/pagalvin