Can't Throw Error from Within an Async Promise Executor Function

Can't throw error from within an async promise executor function

This is the async/await version of the Promise constructor antipattern!

Never ever use an async function as a Promise executor function (even when you can make it work1)!

[1: by calling resolve and reject instead of using return and throw statements]

by "asynchronous" they're not referring to async functions, so I don't think their explanations apply here

They could as well. A simple example where it cannot work is

new Promise(async function() {
await delay(…);
throw new Error(…);
})

which is equivalent to

new Promise(function() {
return delay(…).then(function() {
throw new Error(…);
});
})

where it's clear now that the throw is inside an asynchronous callback.

The Promise constructor can only catch synchronous exceptions, and an async function never throws - it always returns a promise (which might get rejected though). And that return value is ignored, as the promise is waiting for resolve to be called.

Async promise executor functions

You don't need to create a new promise yourself because async functions always return a promise. If the return value of an async function is not a promise, it is implicitly wrapped in a promise.

So you need to remove the code that creates a new promise instance and the code inside the executor function should be at the top-level in the processFolder function.

Your code can be simplified as shown below:

async function processFolder(folder) {
const table = {};
const list = await getHTMLlist(folder);

if (list.length > 0) {
for (let i = 0; i < list.length; i++) {
await processFile(folder, list[i], table);
}
}

return table;
}

Ideally, you should also wrap the code inside the processFolder function in a try-catch block to catch and handle any errors that might occur during the execution of this function.

Is it an anti-pattern to use async/await inside of a new Promise() constructor?

You're effectively using promises inside the promise constructor executor function, so this the Promise constructor anti-pattern.

Your code is a good example of the main risk: not propagating all errors safely. Read why there.

In addition, the use of async/await can make the same traps even more surprising. Compare:

let p = new Promise(resolve => {  ""(); // TypeError  resolve();});
(async () => { await p;})().catch(e => console.log("Caught: " + e)); // Catches it.

Correct error handling of nested async functions with promise

No you cannot catch same error twice. The method of relaying error will be buggy. instead what I would do is to just forward the outputs and handle them in the outer function.

const innerFunction = async () => asyncFunction(false); // <-- Just return the outputs
const outerFunction = async () => {
try {
const result = await innerFunction(); // <-- Error is forwarded and thus handled
} catch (error) {
console.log("Caught error inside outerFunction");
}
};

How to properly handle reject in Promises

Couple of problems in your code:

  • You are unnecessarily creating a promise; auth.post(..) already returns a promise, so you don't need to create a promise yourself and wrap auth.post(...) inside a promise constructor.

  • Another problem in your code is that executor function (function passed to the promise constructor) is marked as async; it should not be an async function.

Your function could be re-written as:

const userLogin = async (loginData) => {
const res = await auth.post("/login", loginData);

if (res.status !== 201) {
throw new Error("Error"));
}

return res;
};

You could also re-write your function as:

const userLogin = async (loginData) => {
return auth.post("/login", loginData);
};

Don't forget to use the catch in the code that calls this function.

You might want to read the following article to understand whether you need the try-catch block: await vs return vs return await

Promise constructor with reject call vs throwing error

Is there any difference between using reject (in p2) from the Promise api, and throwing an error (in p1) using throw?

Yes, you cannot use throw asynchronously, while reject is a callback. For example, some timeout:

new Promise(_, reject) {
setTimeout(reject, 1000);
});

Its exactly the same?

No, at least not when other code follows your statement. throw immediately completes the resolver function, while calling reject continues execution normally - after having "marked" the promise as rejected.

Also, engines might provide different exception debugging information if you throw error objects.

For your specific example, you are right that p1 and p2 are indistinguishable from the outside.

js async/await throws error on using this keyword

You are creating a new function

return new Promise((resolve,reject)=>{

you should declare that function as async too:

return new Promise(async (resolve,reject)=>{

The new function will be

async function encodeName(x){
return new Promise(async (resolve,reject)=>{
const cipher = crypto.createCipher('aes192', this.PASSWORD);
let encrypted = cipher.update(x,'utf8', 'hex');
encrypted += cipher.final('hex');
if(encrypted.length>240){
let x = await this.storeFileName(encrypted);
resolve(`@Fn ${x}`);
}
resolve(encrypted);
});
}


Related Topics



Leave a reply



Submit