En detaljerad guide till felsökning av JavaScript-kod i Chrome Devtools. Stoppar när DOM ändras


Föreställ dig att du arbetar med denna otroliga nya webbapplikation och dina testare har bett dig att fixa följande buggar:

  • Statusfältsmeddelandet "Laddar in..." försvinner inte när programmet har laddats klart.
  • Standardspråket är norska, även på engelska versioner IE och Firefox.
  • Någonstans i koden skapades en global variabel prop.
  • Av någon anledning har alla element i DOM-visaren attributet "clone".
  • Kör debuggers
    • I Firefox måste du se till att du har installerat Firebug-tillägg. Välj "Verktyg > Firebug > Öppna Firebug".
    • I Opera 9.5+ väljer du "Verktyg > Avancerat > Utvecklingsverktyg."
    • I IE beta, gå till "Verktyg > Paneler > Utforskarfält > IE Developer Toolbar."
    • I Safari eller WebKit, aktivera först felsökningsmenyn (1), välj sedan "Utveckla > Visa webbinspektör"
    Det är dags att lansera debuggers. Eftersom vissa instruktioner kräver kodändringar, kanske du vill spara en testsida och ladda den från disken i din webbläsare. Fel #1: "Laddar..."-meddelande Om du tittar på programmet du felsöker, kommer du först att se vad. visas i figur 1.


    ris. 1: Inledande vy av vår JavaScript-applikation i Dragonfly respektive Firebug.

    När du tittar på källkoden i debuggern, lägg märke till clearLoadingMessage()-funktionen i början av koden. Det här är ett bra ställe för en checkpoint.

    Så här installerar du det:

  • Klicka i vänstermarginalen på radnumret för att ställa in en brytpunkt på den första raden
  • Ladda om sidan.
  • Observera att brytpunkten måste ställas in på kodraden som kommer att exekveras när funktionen körs. Raden som innehåller clearLoadingMessage() () är inte lämplig eftersom den bara är en funktionsdefinition.

    När sidan laddas om kommer skriptet att sluta köras och du kommer att se vad som visas i figur två.


    ris. 2: debuggers stannade vid Kontrollpunkt inuti clearLoadingMessage.

    Låt oss ta en titt på funktionskoden. Som du lätt kan se uppdaterar den två DOM-element och rad 31 nämner ordet statusfält. Det ser ut som att getElements("p", ("class":"statusrad")).innerHTML letar efter statusfältselementet i DOM-trädet. Hur kan vi snabbt testa vårt antagande?

    Klistra in detta uttalande i kommandoraden för att testa. Figur tre visar tre skärmdumpar (Dragonfly, Firebug och IE8) efter att ha läst innerHTML eller yttre HTML-element, returneras av kommandot du söker efter.

    Gör följande för att kontrollera:

  • Hitta kommandoraden:
    * I Firebug byter du till fliken "Konsol".
    * I Dragonfly, titta under JavaScript-kodpanelen.
    * I IE8, hitta fliken "Konsoll" till höger.
  • Klistra in getElements("p", ("class":"statusrad")).innerHTML på kommandoraden.
  • Tryck enter.



  • ris. 3: Mata ut kommandoresultatet i Dragonfly, Firebug respektive IE8.

    Kommandoraden är mycket användbart verktyg, vilket gör att du snabbt kan testa små kodbitar. Firebug-konsolintegrationen är mycket användbar - om ditt kommando matar ut ett objekt får du en mycket intelligent vy. Till exempel, om det är ett DOM-objekt - kommer du att se det uppmärkta resultatet.

    Du kan använda konsolen för att göra mer djupgående forskning. JavaScript-sträng, som vi studerar, gör följande tre saker:

  • Får en referens till statusfältselementet.
  • Hittar firstChild, med andra ord, den första noden i detta stycke.
  • Ställer in egenskapen innerText.
  • Låt oss försöka köra något mer än det föregående kommandot i konsolen. Du kan till exempel försöka ta reda på vad det aktuella värdet för egenskapen innerText är innan du tilldelar den ett nytt värde. För att ta reda på det kan du skriva in hela kommandot upp till "="-tecknet på kommandoraden: getElements("p" , ("class":"statusbar")).firstChild.innerText

    Överraskning, på slutet... ingenting. Således pekar uttrycket getElements("p",("class:"statusbar")).firstChild på något objekt i DOM som inte innehåller någon text, eller som inte har en innerText-egenskap.

    Sedan är nästa fråga: vad kommer egentligen först? barnelement vid stycket? Låt oss ställa den här frågan på kommandoraden. (Se fjärde bilden).

    ris. 4: kommandorad StDragonfly debugger, utgång [Textobjekt].

    Dragonflys debugger-utgång - [Textobjekt] visar att detta är en DOM-textnod. Därmed hittade vi orsaken till det första problemet. En textnod har inte en innerText-egenskap, därför gör det ingenting att sätta p.firstChild.innerText till ett värde. Detta fel kan enkelt fixas genom att ersätta innerText med nodeValue, som är en egenskap som definieras av W3C-standarden för textnoder.

    Nu när vi har tagit itu med det första felet:

  • Klicka eller Kör-knappen för att avsluta skriptet.
  • Glöm inte att återställa den inställda kontrollpunkten genom att klicka på radnumret igen.
  • Misstag två: språkdefinitionsproblem. Du kanske har lagt märke till variabeln lang;/*language*/ i början av skriptet. Man kan misstänka att koden som ställer in värdet på denna variabel orsakar problemet. Du kan försöka hitta den här koden med hjälp av sökfunktionen som är inbyggd i debuggers. I Dragonfly finns sökningen precis ovanför kodvisaren, i Firebug är den till höger övre hörnet(se bild 5)

    Gör följande för att ta reda på var lokaliseringsproblemet sannolikt uppstår:

  • Skriv lang = i sökfältet.
  • Ställ in en brytpunkt på linjen där variabeln lang är satt till ett värde.
  • Ladda om sidan.
  • WebInspector har också mycket bekväm funktion Sök. Det låter dig söka efter vad som helst samtidigt i sidmarkering, CSS och JavaScript-kod. Resultaten visas i en separat panel, där du kan dubbelklicka på dem för att gå till önskad plats, som visas på skärmdumpen.


    ris. 5: Sök i Dragonfly och WebInspector.

    För att kontrollera vad den här funktionen gör:

  • Klicka på "steg in"-knappen för att gå in i getLanguage-funktionen.
  • Tryck på den igen och igen, exekvera koden steg för steg
  • I variabelvisningsfönstret kan du se hur deras värden förändras.
  • När du går in i funktionen kommer du att se ett försök att läsa språket från webbläsarens användaragentsträng genom att analysera navigator.userAgent.
    var str1 = navigator.userAgent.match(/\((.*)\)/);
    var ar1 = str1.split(/\s*;\s*/), lang;
    för (var i = 0; i< ar1.length; i++){
    if (ar1[i].match(/^(.(2))$/))(
    lang = ar1[i];
    }
    }

    När du går igenom din kod kan du använda Local Variables Viewer. Figur 6 visar hur det ser ut i Firebug och IE8 DT vi utökade ar1-arrayen för att se dess element.

    ris. 6: Ruta för att visa lokala variabler för getLanguage-funktionen i Firebug IE8

    Uttrycket ar1[i].match(/^(.(2))$/) söker helt enkelt efter en sträng som består av två tecken, till exempel "nej", "en". Men som du kan se på skärmdumpen i Firefox presenteras information om språket i formen "nn-NO" (2). IE lägger inte alls in språkinformation i användaragenten.

    Således hittade vi det andra felet: språket bestämdes genom att söka efter en tvåbokstavskod i användaragentraden, men Firefox har en språkbeteckning på fem tecken, och IE har det inte alls. Sådan kod måste skrivas om och ersättas med språkdetektering antingen på serversidan med hjälp av Accept-Language HTTP-headern eller genom att hämta den från navigator.language (navigator.userLanguage för IE). Här är ett exempel på vad en sådan funktion kan vara

    funktion getLanguage() (
    var lang;

    if (navigator.language) (
    lang = navigator.språk;
    ) else if (navigator.userLanguage) (
    lang = navigator.userLanguage;
    }

    if (lang && lang.length > 2) (
    lang = lang.substring(0, 2);
    }

    return lang;
    }


    Misstag tre: Den mystiska "prop"-variabeln
    ris. 7: Den globala prop-variabeln är synlig i Firebug och Dragonfly-variabelvypanelen

    I figur 7 kan du tydligt se variabeln "prop". I välskrivna applikationer bör antalet globala variabler hållas till ett minimum, eftersom de kan orsaka problem när till exempel två delar av applikationen vill använda samma variabel. Låt oss anta att i morgon kommer ett annat team att lägga till nya funktioner till vår applikation och även deklarera variabeln "prop". Vi kommer att sluta med två olika delar av applikationskoden som använder samma namn för olika saker. Denna situation leder ofta till konflikter och misstag. Du kan försöka hitta denna variabel och deklarera den lokal. För att göra detta kan du använda sökningen, som vi gjorde i föregående fall, men det finns ett smartare sätt...

    Debuggers för många andra programmeringsspråk har konceptet med en "klocka", som går in i felsökningsläge när en specificerad variabel ändras. Varken Firebug eller Dragonfly stöder "observatörer" för närvarande, men vi kan enkelt emulera liknande beteende genom att lägga till nästa rad till början av koden som studeras:

    __defineSetter__("prop" , function () (debugger; ));

    Gör följande:
  • Lägg till felsökningskod i början av det allra första skriptet.
  • Ladda om sidan.
  • Notera hur skriptkörningen avbryts.
  • IE8 DT har en "Titta"-flik, men det blir inget avbrott när en variabel ändras. Så det här exemplet fungerar bara i Firefox, Opera och Safari.

    När du laddar om sidan kommer kodexekveringen omedelbart att stoppas där variabeln "prop" är definierad. Det faktiska stoppet kommer att inträffa vid den punkt där du lade till raden ovan. Ett klick på "steg ut"-knappen tar dig till platsen där variabeln är inställd.

    för (prop i attribut) (
    if (el.getAttribute(prop) != attribut) includeThisElement = false ;


    Det är inte svårt att lägga märke till för slinga där prop-variabeln deklareras utan nyckelord var, dvs. global. Att fixa detta är inte svårt, lägg bara till var och fixa felet: "clone"-attributet, som inte borde finnas där. Det fjärde felet upptäcktes tydligen av en avancerad testare som använder DOM-inspektören, eftersom dess existens inte visas. på något sätt in användargränssnitt applikationer. Om vi ​​öppnar DOM-inspektören (i Firebug är detta fliken "HTML", i Dragonfly kallas det "DOM"), kommer vi att se att många element har klon attribut, som inte borde finnas.

    ris. 8: Dragonflys DOM-inspektör visar problematisk kod.

    Eftersom detta inte påverkar applikationens användare på något sätt, kan det här felet inte betraktas som allvarligt, men glöm inte att det kan påverka prestandan avsevärt, eftersom skriptet ställer in attributet på hundratals och tusentals element.

    Mest snabbt sätt Lösningen på detta problem är att ställa in en brytpunkt som aktiveras när ett attribut som kallas clone sätts på något HTML-element. Kan debuggers göra detta?

    JavaScript är ett mycket flexibelt språk, och ett av dess styrkor(eller svaga, beroende på din synvinkel) är vad du kan ersätta grundläggande funktioner språk med ditt eget. Lägg till denna kodbit på sidan, den kommer att åsidosätta systemmetod setAttribute, vilket gör att koden slutar när egenskapen "clone" är inställd:

    var funcSetAttr = Element.prototype.setAttribute; /* spara en referens till systemmetoden */
    Element.prototype.setAttribute = funktion (namn, värde) (
    if (namn == "klon") (
    felsökare; /* stoppa skriptet */
    }
    funcSetAttr.call(detta, namn, värde); /* anropa en tidigare sparad systemmetod så att normala egenskaper ställs in korrekt */
    };

    Så vi gör följande:
  • Lägg till följande kod i början av det första skriptet på sidan.
  • Ladda om sidan.
  • Efter en omstart börjar skriptet bearbeta DOM-trädet, men slutar omedelbart så snart ett "dåligt" attribut har ställts in. (Observera att nuvarande Firefox-versioner, är implementeringen av setAttribute annorlunda för olika element. Koden ovan fungerar alltid som den ska bara i Opera; För att få samma effekt i Firefox kan du ersätta ordet Element med HTMLFormElement för att åsidosätta den mer specifika HTMLFormElement.prototype.setAttribute-metoden).

    När exekveringen stannar vid en brytpunkt, vill du veta var setAttribute()-anropet inträffade, vilket betyder att du måste gå tillbaka upp i funktionsanropskedjan och se vad som händer där. Du kan använda en samtalsstack för detta.


    ris. 9: Ring stack i Dragonfly och IE8.

    Figur 10 visar stacken i Firebug. I kö " setAttribute





    

    2024 gtavrl.ru.