NodeJS: async.queue zeigt standardmäßig keine Fehlermeldungen an

Derzeit erstelle ich einen benutzerdefinierten Web-Crawler und die einfachste Methode zur Implementierung von parallelen Funktionen ist die Verwendung des npm-Pakets „async“.

Während des Programmierens stieß ich auf das Problem, dass das Programm nicht richtig funktionierte, aber das Terminal keine Fehler anzeigte.

Also habe ich die Warteschlangenfunktion außerhalb von async getestet und sie hat wie erwartet einen Fehler angezeigt. Was war hier los?

Es stellte sich heraus, dass async.queue standardmäßig Fehler abfängt und dass man sie explizit behandeln muss. Dies kann durch Hinzufügen eines Fehler-Callbacks zur Warteschlange erfolgen:

var q = async.queue(function(task, callback) {
    console.log('hello ' + task.name);
    callback();
}, 2);

q.error(function(err, task) {
    console.error('task experienced an error');
});

Derzeit ist dies nicht sehr hilfreich, aber natürlich können Sie den Fehler leicht anzeigen:

q.error(function(err, task) {
    console.error(`Async error: ${err}`);
});

Da haben wir es:

Async error: ReferenceError: xxx is not defined


(Photo by LOGAN WEAVER | @LGNWVR on Unsplash)

Wochenend-Projekt: Jump to Header

Vor einiger Zeit ist mir der Browser “Nyxt” über den Weg gelaufen. Ein Feature fand ich besonders praktisch, nämlich die Möglichkeit, die Überschriften (<H1> bis <H6″>) in einem Sidepanel anzuzeigen.

Chrome verfügt seit einiger Zeit ebenfalls über einen Sidepanel. In diesem könnte man doch das gleiche Feature anzeigen. Eine kurze Suche im Webstore ergab, dass es eine entsprechende Extension nicht gibt. Es sollte doch nicht schwer sein, so etwas nachzubauen.

Am Ende war es doch etwas schwieriger als gedacht, aber doch machbar. Das Ergebnis ist die Extension “Jump to Heading“, die in einer frühen Version auf Github verfügbar ist.

Momentan muss die Extension noch über “Load unpacked installiert werden, da sie auf alle URLs zugreifen muss, und mit dieser Einstellung dauert der Review bei Google immer etwas länger (und meistens haben die auch noch was anderes zu meckern).

Download: Jump to Heading v0.1

Update: Die Extension ist jetzt im Web Store erhältlich.

JavaScript: Die console() kann mehr als Du denkst

Für den eiligen Leser:

  1. Variablennamen ausgeben
  2. Variablen tabellarisch ausgeben
  3. Funktionsnamen ausgeben
  4. Ausführungszeit messen
  5. Ausgabe gruppieren
  6. Ausgabe in mehreren Ebenen
  7. Platzhalter
  8. console.assert()

Wie jeder Entwickler von Webanwendungen muss ich mich endgültig einmal intensiver mit ECMAScript (früher JavaScript) beschäftigen.

Die klassische Variante Javascript zu debuggen ist die Ausgabe in die Konsole. Die Nutzung eines “echten” Debuggers wird von Vielen propagiert, aber ein kurzes console.log geht dann häufig doch schneller.
(Bitte keine Diskussion über die Nutzung von Debuggern in den Kommentaren! Danke.)

Die console hat aber noch andere Funktionen als ein einfaches .log  zu bieten, die das Auffinden eines Fehlers vereinfachen können. Ich möchte hier sechs unbekanntere vorstellen.

Variablennamen ausgeben

Die folgenden Variablen sollen in der Konsole ausgegeben werden:

var1 = 'Hans';
var2 = 'Peter';
var3 = 'Klaus';

Ein einfaches console.log(var1, var2, var3);  ergibt folgende Ausgabe:

Hans Peter Klaus

Hat man den Code gerade eben geschrieben, so weiß man sicherlich noch, welche Variablen hier ausgegeben werden. Nach einigen Tagen muss man dann aber doch im Code nachsehen, was da eigentlich ausgegeben wird.
Wenn man aus den Variablen ein Objekt macht, werden die Namen der Variablen mit angezeigt:

console.log({var1, var2, var3});

> Object { var1: "Hans", var2: "Peter", var3: "Klaus" }

Variablen tabellarisch ausgeben:

Enthält ein Objekt Elemente, die mehrere Variablen besitzen, so hilft die Ausgabe in Chrome gar nicht und und in Firefox nur bedingt:

var1 = {vorname: 'Hans',  nachname:'Meyer', Alter: 35};
var2 = {vorname: 'Klaus', nachname:'Schulze', Alter: 62};
var3 = {vorname: 'Peter', nachname:'Hoffmann', Alter: 19};

Firefox:

console.log(var1, var2, var3); > Object { vorname: "Hans", nachname: "Meyer", Alter: 35 } Object { vorname: "Klaus", nachname: "Schulze", Alter: 62 } Object { vorname: "Peter", nachname: "Hoffmann", Alter: 19 }

Chrome:

console.log(var1, var2, var3);

> ▶Object ▶Object ▶Object

console.table() erlaubt eine übersichtlichere Darstellung der Werte. Vorher muss man allerdings das Objekt in ein Array verpacken:

console.table([var1, var2, var3]);

Funktionsnamen ausgeben

Werden die gleichen Variablen an mehreren Stellen in der Konsole angezeigt, so sieht man zwar in welcher Zeile der Befehl steht, ab er nicht welche Funktion dafür verantwortlich war. Dies ist insbesondere interessant, wenn man sein Projekt auf viele Dateien verteilt hat:

const var1 = 'Hans';
const var2 = 'Peter';
const var3 = 'Klaus';

const func1 = () =>
    console.trace('>', var1, var2, var3);

const func2 = () =>
    console.trace('>', var1, var2, var3);

func1();
func2();

Chrome (voller Pfad nur als Tooltip):

Firefox (etwas unübersichtlicher, dafür aber mit vollem Dateipfad):

Ausführungszeit messen

Manchmal möchte man wissen, wie lange eine Funktion benötigt. Hier kann console  ebenfalls helfen (in Chrome mit sinnlosen 10 Nachkommastellen):

console.time('schleife');

let i = 0;
while (i < 10000000)
    i++;

console.timeEnd('schleife');

> Chrome:
schleife: 33.2099609375ms   fntest.js:12

> Firefox:
schleife: timer started    fntest.js:6
schleife: 19.94ms          fntest.js:12

Ausgabe gruppieren

Wenn man Daten zum Beispiel in einer Schleife ausgibt, so kann die Konsole sehr schnell zugemüllt werden. Um die Übersicht zu behalten, kann man die Ausgaben zu einer Gruppe zusammenfassen:

let i = 0;
console.groupCollapsed('Gruppe1');
while (i < 10) {
    console.log(i);
    i++;
}
console.log('Ende der Schleife');

console.groupEnd('Gruppe1');

Alle Ausgaben zwischen console.groupCollapsed()  und console.groupEnd()  werden in ein aufklappbaren Ausgabe zusammengefasst (funktioniert im aktuellen Waterfox v56 leider nicht):

 

 

 

 

Ausgabe in mehreren Ebenen

console-Ausgaben werden normalerweise einfach untereinander ausgegeben. Mit console.group() (oder auch mit console.GroupCollapse() hat man jedoch die Möglichkeit mehrere Ebenen darzustellen. Die Erstellung ist jedoch etwas aufwendig:

console.log("Ebene 1");
console.group();
console.log("Ebene 2");
console.group();
console.log("Ebene 3");
console.log("Ebene 3");
console.groupEnd();
console.log("Wieder Ebene 2");
console.groupEnd();
console.log("Wieder Ebene 1");

Platzhalter

In der console  kann man Platzhalter wie z.B. in PHP oder C benutzen:

console.log('Dies ist ein %s in der Console.', 'Platzhalter');

> Dies ist ein Platzhalter in der Console.

Es gibt vier Platzhalter-Symbole:

  • %s – String
  • %d – Float oder Integer
  • %o – Objekt
  • %c – CSS

Der letzte Punkt ist vielleicht etwas überraschen, deshalb folgt ein kleines Beispiel:

console.log(‘Ich bin ein %cwichtiger Text’, ‘color: red’);

Hier erkenn man auch das Problem: Es gibt zwar einen Platzhalter, um den begin des CSS-Bereichs zu kennzeichnen, aber keine Kennzeichnung für das Ende. Man kann es eigentlich nur sinnvoll nutzen, wenn man eine ganze Zeile kennzeichnen möchte:

console.assert()

Diese Methode ist Vielen nicht bekannt, aber durchaus praktisch: Er gibt eine Meldung aus, wenn eine Bedingung nicht erfüllt ist. Ja, richtig gelesen, wenn sie nicht erfüllt ist. Das führt am Anfang zu heftigem Kopfzerbrechen, ich habe mich allerdings nie daran gewöhnt. Hier ein Beispiel. Intuitiv würde man folgendes schreiben, um etwas auszugeben, wenn i  “5” ist:

for (let i=0; i<10; i++) {
    console.assert(i === 5, i);
}

Die Ausgabe ist zunächst überraschend:

Es werden alle Werte ausgegeben außer der “5”. Das liegt daran, dass assert()  alle Werte ausgibt, die nicht der Bedingung entsprechen (“Falsey” sind). Der Code muss also korrekt lauten:

for (let i=0; i<10; i++) {
   console.assert(i !== 5, i);
}
 
Das liegt an dem Begriff “Assert”. “Assertion” bedeutet “Behauptung” und console.assert()  erzeugt eine Ausgabe, wenn die Behauptung falsch ist, also im Fehlerfall. Hat man sich dieses einmal verinnerlicht, kann man diese Methode innvoll einsetzen.
 
—-