archivos mensuales: Enero 2014

Pobre del almacenamiento en caché en JavaScript

[TL;Versión DR: utiliza cookies para almacenar los resultados de las llamadas asincrónicas; prestar inmediatamente los resultados de las últimas llamadas asincrónicas y validarlos luego después de carga de la página.]

He estado trabajando en sitio de intranet de SharePoint para un cliente que ofrece, entre otras cosas, una estilizada navegación secundaria cuyas opciones del menú se administran mediante una lista personalizada vieja regular.  La idea es que el cliente obtiene al menú de "su" sitio de control sin afectar o ser afectados por la navegación global por lo.

(Hay algo increíblemente subversiva con la adición de un CEWP que apunta a un archivo HTML que carga un CSS y JS fundamentalmente modificar casi todo sobre el comportamiento de un sitio... pero eso es para otro post)

El código para esta bastante simple:

El dolor punto aquí es cada vez que alguien golpea una de las páginas del sitio, navegador del usuario es llegar a obtener elementos de la lista.  Una vez termine la dev y pruebas han demostrado que todo sea estable y completa, esta llamada no es necesaria más de 99% el tiempo desde el menú rara vez cambia.  También tiene un raro efecto UI que es común en este nuevo mundo de sitios web de hiper-ajaxy – hace que la página y sólo entonces hace el menú render.  Es nervioso y distracción en mi punto de vista.  Y nervioso. Por lo tanto, almacenamiento en caché. 

Modifiqué la lógica de esta manera:

  • Busque una cookie en el navegador que contiene el menú como último lo leí
    • Si encuentran, hacerla inmediatamente.  No esperes a terminar de cargar la página.  (Usted necesita para asegurarse de que el código HTML está ubicado estratégicamente aquí, Pero no es difícil de hacer).
  • Esperar a que la página termine de cargar y hacer un async llamar a cargar los elementos de menú de una lista utilizando el resto lists.asmx o lo que sea
  • Comparar lo que tengo contra la cookie
    • Si coincide con, PARADA
    • De lo contrario, utilizando jQuery, rellenar dinámicamente un montón si <Li>está en un <UL>
  • Usar CSS para hacer todo el formato
  • Beneficio!

Algunos de ustedes van a decir, "Hola! no habrá verdadera caché aquí puesto que estás leyendo el menú de todos modos cada vez.”  Y tienes razón, no voy a dar al servidor cualquier tipo de rotura.  Pero porque la llamada asincrónica y ocurre después de la Página inicial carga HTML representa plenamente, "parece" más sensible al usuario.  El menú bastante rinde tanto como la página dibuja.  Si el menú pasa al cambio, el usuario se somete a un nervioso volver a dibujar del menú, Pero sólo una vez.

Hay algunas maneras de hacer más eficaz esta caché y ayudar al servidor al mismo tiempo:

  • Poner en una regla que la caché"cookie" es válida para un mínimo de 24 horas o algunos otros plazos. Mientras no hay ninguna cookie caducada, usar copias instantáneas de menú de la cookie y nunca golpeó el servidor.

Bueno... eso es lo que vienen a la mente ahora :). 

Si alguien tiene alguna idea inteligente aquí me encantaría conocerlos.

Y por último – esta técnica puede utilizarse para otras cosas.  Página de mi cliente tiene un número de cosas basadas en datos de varias páginas, muchos de ellos cambiando relativamente raramente (como una vez por semana o una vez al mes).  Si destino áreas específicas de la funcionalidad, Puedes darle una interfaz de usuario más sensible tirando de contenido de la tienda local de galleta y procesamiento inmediato.  Se siente más rápido para el usuario incluso si no estás salvando el servidor cualquier ciclos.  Te puede Guarde los ciclos del servidor por decidir sobre algunas condiciones y disparadores para invalidar esta caché local cookie.  Eso es todo situacional artístico y verdad lo más divertido :). 

</final>

undefinedSuscribirse a mi blog.

Sígueme en Twitter en http://www.twitter.com/pagalvin

Cómo: Configurar prueba unitaria y cobertura de la prueba con QUnit.js y Blanket.js para una oficina 365 Aplicación de SharePoint

Intro

Me han estado explorando pruebas unitarias y cobertura de prueba para JavaScript como trabajo en una nueva aplicación de SharePoint para SharePoint en línea en la oficina 365 Suite.  Los caminos de investigación obvio me llevaron a Qunit.js y justo después, Para Blanket.js.

QUnit Déjame crear pruebas unitarias y agruparlas en módulos.  Un módulo es una manera simple de organizar pruebas relacionadas. (No sé si que lo estoy usando como se pretendía, Pero está funcionando para mí hasta ahora con el pequeño conjunto de pruebas que hasta el momento he definido).

Blanket.js se integra con Qunit y me mostrará las líneas reales de JavaScript que eran – y lo más importante – no fueron realmente ejecutadas en el transcurso de las pruebas.  Esta es "la cobertura" – líneas que ejecutan están cubiertas por la prueba mientras que otras no lo son.

Entre establecer buenos casos de prueba y visualización de cobertura, podemos reducir el riesgo de que nuestro código ha ocultado defectos.  Buenos tiempos.

Qunit

Suponiendo que tienes tu Visual Studio proyecto establecido, empezar descargando el paquete de JavaScript desde http://qunitjs.com.  Añadir el JavaScript y CSS correspondiente a su solución.  Mina se parece a esto:

image

Figura 1

Como se puede ver, Estaba usando 1.13.0 en el momento que escribí esta entrada de blog. No te olvides de descargar y agregar el archivo CSS.

Fuera del camino, siguiente paso es crear una especie de prueba del arnés y los bits de Qunit de referencia.  Estoy probando un montón de funciones en un archivo de script llamado "QuizUtil.js" así que he creado una página HTML llamada "QuizUtil_test.html" como se muestra:

image Figura 2

Aquí está el código:

<!DOCTYPE HTML>
<HTML xmlns= "http://www.w3.org/ 1999/xhtml">
<cabeza>
    <Título>QuizUtil prueba con Qunit</Título>
    <enlace REL= "stylesheet" href="../CSS/qunit-1.13.0.CSS" />
    <secuencia de comandos tipo= text/javascript"" src="QuizUtil.js" datos de la cubierta></secuencia de comandos>
    <tipo de script ="text/javascript" src ="qunit-1.13.0.js"></secuencia de comandos>
    <tipo de script ="text/javascript" src ="blanket.min.js"></secuencia de comandos>

    <secuencia de comandos>
        módulo("getIDFromLookup");
        prueba("QuizUtil getIDFromLookupField", función () {
            var goodValue = "1;#Paul Galvin";

            igual(getIDFromLookupField(goodValue) + 1, 2), "ID de [" + goodValue + "] + 1 debe ser de 2";
            igual(getIDFromLookupField(undefined), undefined, "Undefined argumento de entrada debe devolver resultado indefinido.");
            igual(getIDFromLookupField(""), undefined, "Argumento de entrada vacío debe devolver un valor no definido.");
            igual(getIDFromLookupField("gobbledigood3-thq;ada dkvn;skfja sdjfbvubvqrubqer0873407t534piutheqw;vn"), undefined,"Debería volver un convertible de resultado a un entero");
            igual(getIDFromLookupField("2;#alguna otra persona"), "2", "Checking [2;#alguna otra persona].");
            igual(getIDFromLookupField("9834524;#valor de tipo Long"), "9834524", "Prueba de gran valor.");
            SqlDouble(getIDFromLookupField("5;#Nadie", 6), 6, "Prueba de un SqlDouble (5 No es igual a 6 para este ejemplo: [5;#Nadie]");

        });

        módulo("htmlEscape");
        prueba("QuizUtil htmlEscape()", función () {
            igual(htmlEscape("<"), "&lt;", "Escape a menos de operador ('<')");
            igual(htmlEscape("<div class =  "someclass">Parte del texto</div>"), "&lt;div class =&quot;SomeClass&quot;&gt;Parte del texto&lt;/div&gt;", "La secuencia de prueba más compleja.");
        });

        módulo("getDateAsCaml");
        prueba("QuizUtil getDateAsCaml()", función () {
            igual(getDateAsCaml(Nuevo Fecha("31/12/2013")), "2013-12-31T:00:00:00", "Testing fecha duro codificado: [12/31/2013]");
            igual(getDateAsCaml(Nuevo Fecha("01/05/2014")), "2014-01-05T:00:00:00", "Testing fecha duro codificado: [01/05/2014]");
            igual(getDateAsCaml(Nuevo Fecha("01/31/2014")), "2014-01-31T:00:00:00", "Testing fecha duro codificado: [01/31/2014]");
            igual(getTodayAsCaml(), getDateAsCaml(Nuevo Fecha()), "getTodayAsCaml() debe ser igual a getDateAsCaml(nueva fecha())");
            igual(getDateAsCaml("valor de tonterías"), undefined, "Tratar de obtener la fecha de un valor de tonterías.");
            igual(getDateAsCaml(undefined), undefined, "Tratar de obtener la fecha de la [undefined] fecha.");
        });

        módulo("getParameterByName");
        prueba("QuizUtil getParameterByName (de la cadena de consulta)", función () {
            igual(getParameterByName(undefined), undefined, "Tratar de conseguir parámetro definido debe devolver indefinido.");
            igual(getParameterByName("no existe"), undefined, "Tratar de obtener el valor del parámetro cuando sabemos que no existe el parámetro.");

        });

        módulo(Cookies"");
        prueba("QuizUtil varias funciones de la galleta.", función () {
            igual(setCookie("prueba de", "1", -1), getCookieValue("prueba de"), "Conseguir una galleta puse debería funcionar.");
            igual(setCookie("anycookie", "1", -1), verdadero, "Establecer una cocción válido debe devolver 'true'.");
            igual(setCookie("nombre de la cookie loco !@#$%"%\^&*(()?/><.,", "1", -1), verdadero, "Establecer un nombre de la cookie mal debe devolver 'falso'.");
            igual(setCookie(undefined, "1", -1), undefined, "Paso definido como el nombre de la cookie.");
            igual(getCookieValue("no existe"), "", "Cookie no existe prueba.");
        });

    </secuencia de comandos>
</cabeza>
<cuerpo>
    <div ID.= "qunit"></div>
    <div ID.= "qunit-fixture"></div>

</cuerpo>
</HTML>

Hay varias cosas que pasan aquí:

  1. Mi código de referencia (QuizUtil.js)
  2. Referencia Qunity.js
  3. Definir algunos módulos (getIDFromLookup, "Cookies", y otros)
  4. Colocar un <div> cuyo ID es "qunit".

A continuación, Sólo hago esta página y obtienes algo como esto:

image

Figura 3

Si te ves en la parte superior, Tienes varias opciones, dos de los cuales son interesantes:

  • Ocultar pruebas pasado: Bastante obvio.  Puede ayudar el ojo a ver las áreas problemáticas y no un montón de desorden.
  • Módulo: (menú desplegable): Esto filtrará las pruebas a esos grupos de pruebas que quieres.

En cuanto a las pruebas de sí mismos – unos comentarios:

  • Hace falta decir que tienes que escribir el código que es comprobable en primer lugar.  Usando la herramienta puede ayudar a hacer cumplir esa disciplina. Por ejemplo, Tenía una función llamada "getTodayAsCaml()”.  Esto no es muy comprobable desde no toma ningún argumento de entrada y para probarlo por la igualdad, Necesitamos actualizar constantemente el código de prueba para reflejar la fecha actual.  Yo lo refactorizado por adición de un parámetro de entrada de datos y luego pasar la fecha actual cuando quiera la fecha actual en formato CAML.
  • El marco Qunit documenta sus propias pruebas y parece bastante robusto.  Puede hacer cosas simples como prueba para la igualdad y también tiene soporte para llamadas de estilo ajax (tanto "real" o escarnecido usando tu favorito mocker).
  • El proceso también te obliga a pensar en casos de borde – ¿qué pasa con "indefinido" o nulo se pasa a una función.  Resulta muerto simple probar estos escenarios hacia fuera.  Muy bueno.

Cobertura con Blanket.js

Blanket.js complementa Qunit mediante el seguimiento de las actuales líneas de código que se ejecutan durante el curso de sus pruebas.  Integra el derecho en Qunit así que aunque es una aplicación totalmente independiente, juega muy bien, parece que es una aplicación perfecta.

Esto es blanket.js en acción:

image Figura 4

image

Figura 5

(Tienes que hacer clic en la casilla "Habilitar la cobertura" en la parte superior [ver figura 3] para permitir esto.)

Las líneas resaltadas en la figura 5 No han sido ejecutados por cualquiera de mis pruebas, Tengo que diseñar una prueba que hacen que se ejecutarán si quiero cobertura completa.

Conseguir trabajo siguiendo estos pasos blanket.js:

  1. Descargar de http://blanketjs.org/.
  2. Añádelo a tu proyecto
  3. Actualizar la página de mazo de cables de prueba (QuizUtil_test.html en mi caso) como sigue:
    1. El código de referencia
    2. Decorar tu <secuencia de comandos> referencia así:
    <secuencia de comandos tipo= text/javascript"" src="QuizUtil.js" datos de la cubierta></secuencia de comandos>

Blanket.js recoge el atributo "data-cubierta" y hace su magia.  Se conecta a Qunit, actualiza la interfaz de usuario para agregar la opción "Habilitar la cobertura" y listo!

Resumen (TL; DR)

Utilizar Qunit para escribir sus casos de prueba.

  • Descargar
  • Añádelo a tu proyecto
  • Escribir una página de prueba de arnés
  • Crear tus pruebas
    • Refactorizar algunas de tu código para ser comprobable
    • Ser creativo!  Creo que de locos, escenarios imposibles y ponerlas a prueba de todos modos.

Blanket.js de uso para asegurar una cobertura

  • Asegúrese de que está trabajando Qunit
  • Descargar blanket.js y agregarla a su proyecto
  • Agregar a la página de mazo de cables de prueba:
    • Agregue una referencia a blanket.js
    • Agregar un atributo "datos-cubierta" para su <secuencia de comandos> etiqueta
  • Ejecutar las pruebas Qunit.

Nunca hice nada de esto antes y tenía algo rudimentario en un puñado de horas de trabajo. 

Prueba feliz!

</final>

undefinedSuscribirse a mi blog.

Sígueme en Twitter en http://www.twitter.com/pagalvin