OP's usage is not completely described, but the OP's comment "BTW I didn't want to create a stack trace for every forbidden error because I don't want to leak details about my app. So I prefer to create the rejection only once." leads me to believe that at least part of the OP's motivation is to prevent info leakage from unhandled rejections of forbidden
.
Returning a rejected (but defused) promise behaves differently in a sync vs. an async function. In the former the promise is returned verbatim. In the latter it is rewrapped in a promised and automatically rethrown (equivalent to throwing from inside the function). Whichever use was intended, it makes the program harder to understand.(Wrapping the Promise to be returned in an object or array would solve that problem).
Difference in behavior between sync and async funcs when returning forbidden
:
async function test(){
try {
let a = await (async()=>{return forbidden;})();
} catch(e){console.log(e.message);} // outputs: 'FORBIDDEN'
try {
let a = (()=>{return forbidden;})();
// error undetected
} catch(e){console.log(e.message);} // never reaches here !!!
console.log("something else"); // outputs: something else
let a=(()=>{return forbidden;})(); // UHR + '#<Promise>' + no addr
console.log("something else"); // outputs: something else
await (async()=>{return forbidden;})(); // UHR + '#<Promise>' + no addr leak}
}
test();
- Regardless of the the OP's usuage, leakage of program info from unhandled-rejections is a valid concern.
The below factory function makeError
would provide a general solution, and it builds on the OP's original inspiration:
const verboten=new Error('verbotten');
const makeError = () => verboten;
async function test2(){
try {
await (async()=>{throw makeError();})();
} catch(e){console.log(e.message);} // outputs: 'verboten'
// uncomment the following to trigger UHR (unhandled rejection)
//await (async()=>{throw makeError();})(); // UHR + 'verboten' + no addr leak
}
Note that makeError
returns the constant object verboten
, rather than itself. (Yes, that is allowed, although it is rarely used.) So the stack trace is a fixed value, unrelated to the error location in the program, just like the original OP's forbidden
.
That's fine for the release version, but a minor change to makeError
could be made for a development version, where seeing the stack is useful:
const makeError = Error;