javascript - Hvorfor bryder VS Code ved håndteret undtagelse fra Reject i Promise?
Tag denne kode, vi har et promise, der kalder en funktion, som vil fejle, og det burde sende fejlen videre til catch-metoden af promise'et.
Det fungerer helt fint, når det køres fra terminalen. Dog når det køres gennem VSCode, eksploderer det ved (1).
function failingFunc() {
let undef = undefined;
return undef.nope();
}
let promise = new Promise((resolve, reject) => {
resolve(failingFunc()); // (1) Explodes when run from vscode
});
promise.then(v => {}).catch((e: Error) => {
console.log(e.message); // (2) Prints when run from the terminal
});
Hvorfor er det sådan?
vscode om side:
Version 1.14.2
Commit cb82feb
Dato 2017-07-19T23:26:08.116Z
Shell 1.6.6
Renderer 56.0.2924.87
Node 7.4.0
Svar #1
Løsning
Som @T.J.Crowder påpegede i kommentarerne:
Dette sker kun, når en undtagelse kastes, hvilket forårsager en afvisning, før en håndtering er tilføjet. F.eks. ville dette ikke forårsage det, fordi når undtagelsen konverteres til afvisning, er der allerede en afvisningshåndtering tilføjet:
new Promise((resolve, reject) => setTimeout(() => {
try {
throw new Error();
} catch (e) {
reject(e);
}
}, 0)).catch(error => console.log("Error:", error));
Det viser sig, at dette er en kendt "bug", når man bruger vscode til at debugge Nodejs. Som det forklares i dette issue (ovre på vscode-git-repositoriet) sker dette, fordi Nodejs sender en break-event med en undefined undtagelse, hver gang det støder på en reject callback. Når vscodes debugger ser denne break-event, gør den, hvad den skal gøre med ukendte undtagelser, den pauser udførelsen og kaster derefter undtagelsen.
Ydermere siger @roblourens i dette issue (ovre på vscode-node-debug2 repositoriet):
Hvis et løfte afvises, før en fejlhåndtering er tilknyttet, vil debuggeren stoppe, selvom kun "ukatchende undtagelser" er markeret. Hvis det afvises efter, at fejlhåndteringen er tilknyttet, fungerer det som forventet. Og virkelig er problemet den måde, hvorpå løftet ikke ved, om dets afvisning vil blive håndteret eller ej.
Du kan stadig bruge vscode til at udvikle Promise-baserede systemer, men du skal slå al fejlhåndtering fra i vscode. Som vist nedenfor, sørg for, at ingen af mulighederne er markeret.
BEMÆRK: Da dette langt fra er en optimal løsning, er det sandsynligt, at det vil blive ændret og/eller forbedret i fremtiden.
(Jeg har kommenteret på vscode-problemet og vil opdatere dette indlæg, hvis jeg lærer noget nyttigt)
Redigering1:
Jeg har fundet ud af, at en anden løsning er at definere en tastaturgenvej i VSCode til at køre kommandoen workbench.action.debug.run. Dette vil køre den aktuelt valgte debug-mulighed uden at tilknytte debuggeren til den. Det betyder, at du kan beholde debuggeren på dine normale indstillinger, mens du kører koden ved hjælp af den nye tastaturkommando, når du har brug for at arbejde med afviste promises.
/* keybindings.json */
[
{
"key": "ctrl+shift+b",
"command": "workbench.action.debug.start"
/* Attaches debugger */
},
{
"key": "ctrl+b",
"command": "workbench.action.debug.run"
/* Runs without debugger */
}
]
Edit2:
Som @T.J.Crowder påpegede i kommentarerne:
Dette sker kun, når en undtagelse kastes, hvilket forårsager en afvisning, før en håndtering er tilføjet. F.eks. ville dette ikke forårsage det, fordi når undtagelsen konverteres til afvisning, er der allerede en afvisningshåndtering tilføjet:
new Promise((resolve, reject) => setTimeout(() => {
try {
throw new Error();
} catch (e) {
reject(e);
}
}, 0)).catch(error => console.log("Error:", error));
Og selvfølgelig havde han ret. Koden nedenfor virker i VSCode med debuggeren tilsluttet.
function failingFunc() {
let undef = undefined;
return undef.nope();
}
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(failingFunc())
} catch (e) {
reject(e);
}
}, 0);
});
promise.then(v => {}).catch((e: Error) => {
console.log(e.message); // Cannot read property 'nope' of undefined
});
