wake-up-neo.com

Wie lässt sich der "Auslöser" der lokal erfassten Ausnahme beheben?

Bei dieser Funktion, die einen REST -API-Aufruf abwickelt, kann jede der aufgerufenen Funktionen, die Teile der Anforderung behandeln, einen Fehler auslösen, um zu signalisieren, dass ein Fehlercode als Antwort gesendet werden soll. Die Funktion selbst kann jedoch auch einen Fehler entdecken, an dem sie in den Ausnahmebehandlungsblock springen soll.

static async handleRequest(req) {
    try {
        let isAllowed = await checkIfIsAllowed(req);
        if (!isAllowed) {
            throw new ForbiddenException("You're not allowed to do that.");
        }
        let result = await doSomething(req); // can also raise exceptions
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}

Webstorm unterstreicht die throw mit der folgenden Meldung: 'throw' of exception caught locally. This inspection reports any instances of JavaScript throw statements whose exceptions are always caught by containing try statements. Using throw statements as a "goto" to change the local flow of control is likely to be confusing.

Ich bin jedoch nicht sicher, wie ich den Code umwandeln soll, um die Situation zu verbessern.

Ich könnte den Code aus dem catch-Block in die if-Prüfung kopieren, aber ich glaube, das würde meinen Code weniger lesbar machen und schwieriger zu warten sein.

Ich könnte eine neue Funktion schreiben, die die isAllowed-Prüfung durchführt und eine Ausnahmebedingung auslöst, wenn dies nicht gelingt. Dies scheint jedoch das Problem zu umgehen, anstatt ein Designproblem zu beheben, das angeblich von Webstorm gemeldet wird.

Verwenden wir Ausnahmen auf eine schlechte Weise, und deshalb stoßen wir auf dieses Problem, oder ist der Webstorm-Fehler irreführend und sollte deaktiviert werden?

16
cib

Sie suchen nach etwas und werfen eine Ausnahme aus, wenn isAllowed fehlschlägt, aber Sie wissen, was in dieser Situation zu tun ist - rufen Sie sendErrorCode auf. Sie sollten Ausnahmen an externe Anrufer senden, wenn Sie nicht wissen, wie mit der Situation umgegangen wird - dh in Ausnahmefällen.

In diesem Fall haben Sie bereits einen definierten Prozess, was zu tun ist, wenn dies geschieht - verwenden Sie es direkt ohne den indirekten Wurf/Fang:

static async handleRequest(req) {
    try {
        let isAllowed = await checkIfIsAllowed(req);
        if (!isAllowed) {
            sendErrorCode("You're not allowed to do that.");
            return;
        }
        let result = await doSomething(req); // can also raise exceptions
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}

Ich könnte den Code aus dem catch-Block in die ifcheck kopieren, aber ich glaube, das würde meinen Code weniger lesbar machen und schwieriger zu warten sein.

Im Gegenteil, wie oben erwarte ich, dass dies der Weg ist, um mit dieser Situation umzugehen.

20
James Thorpe

Da dies kein Blockierungsfehler ist, sondern nur eine IDE Empfehlung, sollte die Frage von zwei Seiten betrachtet werden.

Die erste Seite ist Leistung. Wenn dies ein Engpass ist und möglicherweise beim Kompilieren oder bei der Übertragung auf neue (noch nicht veröffentlichte) Versionen von nodejs verwendet werden kann, ist das Vorhandensein von Wiederholungen nicht immer eine schlechte Lösung. Es scheint, dass die IDE genau in diesem Fall andeutet und dass ein solches Design in einigen Fällen zu einer schlechten Optimierung führen kann.

Die zweite Seite ist das Code-Design. Wenn dadurch der Code lesbarer wird und die Arbeit für andere Entwickler vereinfacht wird, behalten Sie ihn. Unter diesem Gesichtspunkt wurden bereits Lösungen vorgeschlagen.

1
SlowSuperman

Es gibt gute Antworten auf die Frage "Warum nicht Ausnahmen als normale Ablaufsteuerung verwenden?" hier .

Der Grund, eine Ausnahme, die Sie lokal abfangen, nicht auszulösen, besteht darin, dass Sie lokal wissen, wie Sie mit dieser Situation umgehen sollen. Dies ist per Definition keine Ausnahme.

@ James Thorpes Antwort sieht für mich gut aus, aber @matchish fühlt, dass es DRY verletzt. Ich sage, dass dies im Allgemeinen nicht der Fall ist. DRY, was für Don't Repeat Yourself steht, wird von den Leuten definiert, die den Ausdruck "Jedes Stück Wissen muss eine einzige, eindeutige, maßgebliche Repräsentation innerhalb eines Systems haben" geprägt haben. Beim Schreiben von Software-Code geht es darum, keinen komplexen Code zu wiederholen.

Praktisch jeder Code, von dem behauptet wird, er verstoße gegen DRY=), wird als "repariert" bezeichnet, indem der wiederholte Code in eine Funktion extrahiert und diese Funktion dann an den zuvor wiederholten Stellen aufgerufen wird Ihr Code-Aufruf sendErrorCode ist die Lösung , um ein DRY) - Problem zu beheben Was mit dem Fehler zu tun ist, steht an einer bestimmten Stelle, nämlich der Funktion sendErrorCode.

Ich würde die Antwort von @James Thorpe leicht ändern, aber es ist eher ein Streit als eine wirkliche Kritik, nämlich, dass sendErrorCode Ausnahmegegenstände oder Zeichenfolgen erhalten sollte, aber nicht beides:

static async handleRequest(req) {
    try {
        let isAllowed = await checkIfIsAllowed(req);
        if (!isAllowed) {
            sendErrorCode(new ForbiddenException("You're not allowed to do that."));
            return;
        }
        let result = await doSomething(req); // can also raise exceptions
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}

Die größere Frage ist, wie wahrscheinlich der Fehler ist und ob es angebracht ist, !isAllowed als eine Ausnahme. Ausnahmen sollen ungewöhnliche oder unvorhersehbare Situationen behandeln. Ich würde erwarten !isAllowed ein normales Ereignis sein, das mit einer für diese Situation spezifischen Logik behandelt werden sollte, im Gegensatz beispielsweise zu einer plötzlichen Unfähigkeit, die Datenbank abzufragen, die die Antwort auf die Frage isAllowed enthält.

@ matchish's vorgeschlagene Lösung ändert den Vertrag von doSomethingOnAllowedRequest von etwas, das niemals eine Ausnahme auslöst, in etwas, das routinemäßig eine Ausnahme auslöst, wodurch alle seine Aufrufer mit der Ausnahmebehandlung belastet werden. Dies führt wahrscheinlich zu einer Verletzung von DRY durch die Wiederholung des gleichen Fehlerbehandlungscodes durch mehrere Aufrufer. In der Zusammenfassung mag ich das also nicht. In der Praxis würde es vom abhängen Gesamtsituation, z. B. wie viele Anrufer dort sind und ob sie tatsächlich die gleiche Reaktion auf Fehler haben.

1
Old Pro

Die Antwort von James Thorpe hat meiner Meinung nach einen Nachteil. In beiden Fällen ist es nicht DRY, wenn Sie sendError aufrufen, behandeln Sie Exceptions. Stellen wir uns vor, wir haben viele Codezeilen mit einer solchen Logik, in der Exception geworfen werden kann. Ich denke es kann besser sein.

Das ist meine Lösung

async function doSomethingOnAllowedRequest(req) {
    let isAllowed = await checkIfIsAllowed(req);
    if (!isAllowed) {
       throw new ForbiddenException("You're not allowed to do that.");
    }
    doSomething(req);
}
static async handleRequest(req) {
    try {
        let result = await doSomethingOnAllowedRequest(req);
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}
0
matchish