How to catch a callback error with a try catch? - javascript

I have an async function that grabs the contents of a file, like so:
async function getFile (name) {
return new Promise(function (resolve, reject) {
fs.readFile(`./dir/${name}.txt`, 'utf8', function (error, file) {
if (error) reject(error)
else resolve(file)
})
})
}
And I call that function into a console log
getFile('name').then( console.log )
If I make an error, like misspelling the file name, I get this handy error:
(node:17246) UnhandledPromiseRejectionWarning: Unhandled promise
rejection. This error originated either by throwing inside of an async
function without a catch block, or by rejecting a promise which was not
handled with .catch(). (rejection id: 1)
I can fix it by doing this:
getFile('name').then( console.log ).catch( console.log ) but is there a way to deal with the error within the callback? Perhaps a try catch? How would I do that?

You still need to catch errors that are rejected.
I think it's where you call your getFile function from - that needs to be wrapped in a try/catch block
try {
const result = await getFile('name')
} catch(e) {
... You should see rejected errors here
}
Or, I think this would work for your example:
await getFile('name').then( console.log ).catch(e => {...})
Testing this in the Chrome DevTools console:
async function test () {
return new Promise(function(resolve, reject) {
throw 'this is an error';
})
}
And calling it via the following:
await test().catch(e => alert(e))
Shows that this does, in fact, work!

If I understand correctly, you want your function to resolve regardless of whether you got and error or not. If so you can just resolve in either case:
async function getFile (name) {
return new Promise(function (resolve, reject) {
fs.readFile(`./dir/${name}.txt`, 'utf8', function (error, file) {
if (error) resolve(error)
else resolve(file)
})
})
}
Then you'd need to handle the errors outside, e.g.
getFile('name')
.then(getFileOutput => {
if (getFileOutput instanceof Error) {
// we got an error
} else {
// we got a file
}
})
or
const getFileOutput = await getFile('name');
if (getFileOutput instanceof Error) {
// we got an error
} else {
// we got a file
}
Is that what you're looking for?

Related

can't get an expect console output when using async await

function fails4() {
return new Promise((resolve, reject) => {
setTimeout(function () {
reject(new Error());
}, 100);
});
}
async function myFunc4() {
try {
await fails4();
} catch (e) {
console.log(e);
console.log('that failed', e); //<-- this gets called
}
}
async function loadmYScript() {
try {
await myFunc4();
} catch (error) {
console.log(error);
console.log(123);
}
}
loadmYScript();
cant't execute the console.log(123) as I expected can anybody help me with this question very appreciated
You're calling loadmYScript, which in turn calls myFunc4, which in turn calls fails4. This last one (fails4) throws an error. The error is "catch-ed" by myFunc4. Inside this catch block you don't throw any error, there's only a couple of logs, so the result of loadmYScript is a fulfilled promise with undefined value. It is not rejected because myFunc4 doesn't throw the error.
If you throw an error inside the catch block of myFunc4, you will have your 123 logged, and the promise will be rejected.

How to call an API twice if there is an error occurred?

I have an internal API that I would like to post data. Depends on some cases, I am seeing errors. So what I would like to do is to call it again if there is an error occurred.
What I did was to create a counter to pass it to the function and call the function recursively as below. This gives me the error as below:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
Here is how I call the function:
....
private RETRY_API = 1;
....
try {
await this.callAPI(request, this.RETRY_API);
} catch (error) {
console.log('error', error);
}
This program never comes to the catch block above.
And here is my actual function that I call the API:
private async callAPI(request, retry) {
return new Promise((resolve, reject) => {
someService.postApiRequest('api/url', request, async(err: any, httpCode: number, data) => {
if (this.RETRY_API == 2) {
return reject(err);
} else if (err) {
this.callAPI(request, retry);
this.RETRY_API++;
} else if ( httpCode !== 200 ) {
this.RETRY_API = 2;
// some stuff
} else {
this.RETRY_API = 2;
// some stuff
return resolve(data);
}
});
})
}
Not sure what I am missing. If there is a better way to call the API twice if an error occurred, that would be great if you let me know.
Let's organize a little differently. First, a promise-wrapper for the api...
private async callAPI(request) {
return new Promise((resolve, reject) => {
someService.postApiRequest('api/url', request,(err: any, httpCode: number, data) => {
err ? reject(err) : resolve(data);
});
});
}
A utility function to use setTimeout with a promise...
async function delay(t) {
return new Promise(resolve => setTimeout(resolve, t));
}
Now, a function that calls and retries with delay...
private async callAPIWithRetry(request, retryCount=2, retryDelay=2000) {
try {
return await callAPI(request);
} catch (error) {
if (retryCount <= 0) throw err;
await delay(retryDelay);
return callAPIWithRetry(request, retryCount-1, retryDelay);
}
}
If you can't force a failure on the api to test the error path some other way, you can at least try this...
private async callAPIWithRetry(request, retryCount=2, retryDelay=2000) {
try {
// I hate to do this, but the only way I can test the error path is to change the code here to throw an error
// return await callAPI(request);
await delay(500);
throw("mock error");
} catch (error) {
if (retryCount <= 0) throw err;
await delay(retryDelay);
return callAPIWithRetry(request, retryCount-1, retryDelay);
}
}
It looks like you need to add return await to the beginning of the line this.callAPI(request, retry); in callAPI function.
Similarly there are some condition blocks that doesn't resolve or reject the promise. While it might work okay, it's considered bad practice. You want to either resolve or reject a promise.
I've accomplished calling an API a second time when I received an error by using axios' interceptors functions.
Here is a code snippet you can review:
axios.interceptors.response.use(
// function called on a successful response 2xx
function (response) {
return response;
},
// function called on an error response ( not 2xx )
async function (error) {
const request = error.config as AxiosRequestConfig;
// request is original API call
// change something about the call and try again
// request.headers['Authorization'] = `Bearer DIFFERENT_TOKEN`;
// return axios(request)
// or Call a different API
// const new_data = await axios.get(...).then(...)
// return new_data
// all else fails return the original error
return Promise.reject(error)
}
);
Try replacing
if (this.RETRY_API == 2)
with
if (this.RETRY_API > 1)

"await is only valid in async function" in for loop

I'm being told that "await is only valid in async function", even though it is in a async function. Here is my code:
async function uploadMultipleFiles (storageFilePaths,packFilePaths,packRoot) {
return new Promise((resolve,reject) => {
try {
for (i in storageFilePaths) {
await uploadFile(storageFilePaths[i],packFilePaths[i],packRoot) // error throws on this line
}
resolve("files uploaded")
} catch {
console.log(err)
reject("fail")
}
})
}
Why is this happening when I made it an async function? Is it because I am using a for loop? If so, how can I get the expected outcome without this error?
The function you define starting on line 1 is async.
The arrow function you define on line 2 and pass to the Promise constructor is not async.
You are also using the multiple promise anti-pattern. Get rid of the Promise constructor entirely. Just return the value when you have it. That's one of the main benefits of the async keyword.
async function uploadMultipleFiles(storageFilePaths, packFilePaths, packRoot) {
try {
for (i in storageFilePaths) {
await uploadFile(storageFilePaths[i], packFilePaths[i], packRoot) // error throws on this line
}
return "files uploaded";
} catch {
console.log(err);
throw "fail";
}
}
You can only use await inside of an async function, the error refers to the callback your passing to your new Promise (since you are entering a new function scope there).
async function uploadMultipleFiles (storageFilePaths,packFilePaths,packRoot) {
return new Promise((resolve,reject) => { // <========= this arrow function is not async
try { // so you cant use await inside
for (i in storageFilePaths) {
await uploadFile(storageFilePaths[i],packFilePaths[i],packRoot) // error throws on this line
}
resolve("files uploaded")
} catch {
console.log(err)
reject("fail")
}
})
}
The part where you try to construct a new Promise is actually redundant since an async function will resolve to a Promise anyways (read more here). So you could write your code as follows:
async function uploadMultipleFiles (storageFilePaths,packFilePaths,packRoot) {
try {
for (i in storageFilePaths) {
await uploadFile(storageFilePaths[i],packFilePaths[i],packRoot) // error throws on this line
}
return "files uploaded"
} catch {
console.log(err)
throw new Error("fail");
}
}
The Promise callback isn't async
async function uploadMultipleFiles (storageFilePaths,packFilePaths,packRoot) {
return new Promise(async (resolve,reject) => {
try {
for (i in storageFilePaths) {
await uploadFile(storageFilePaths[i],packFilePaths[i],packRoot) // error throws on this line
}
resolve("files uploaded")
} catch {
console.log(err)
reject("fail")
}
})
}

Node-Soap - throwing fault in async method

Created a soap api with the node-soap library but when i try to throw a fault using
throw {
Fault: {
Code: {
Value: 'soap:Sender',
Subcode: { value: 'rpc:BadArguments' }
},
Reason: { Text: 'Processing Error' }
}
};
as descibed in the library i get a
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
this is what i am currently doing
ssm.decrypt(args.request, password, base_key)
.then(function (res) {
console.log(res)
parseString(res, async function (err, result) {
if (err) {
//the throws causes the error
throw {
Fault: {
error: {
data: {
error
} //Error object from catch
}
}
};
} else {
//some code
}
thanks
Throwing an error inside the async function
parseString(res, async function (err, result)...
rejects the promise returned by the async function - for which there is no catch handler. If parseString calls its callback synchronously, you could just remove the async declaration leaving the call as
parseString(res, function (err, result)...
If parseString is asynchronous, however, it needs to be promisified so errors can be worked into the surrounding promise chain. As an untested example:
function doParseString( res) {
return new Promise( function( resolve, reject) {
parseSting( res, function( err, result) {
err ? reject( err) : resolve( result);
});
});
}
which could be used along the lines of
ssm.decrypt(args.request, password, base_key)
.then( doParseString)
.then( function (result) {
// some code
})
.catch( console.log); // do something with the error
Thanks, guys for your help but I got the issue
if an async function is been used for the soap api been implemented with node-soap
communication need to be done via callbacks
i changed the throw to
callback({
Fault: {
error: {
data: {
error
}
}
}
});
and it works perfectly
i found it here node-soap doc

Unable to handle errors in javascript promise

Why doesn't it run the code "console.log(err)" below? but instead returns "TypeError: Cannot create property 'uncaught' on string 'error in promise'"
function abc() {
throw "error in promise";
return 123;
};
abc().catch(function(err) {
console.log(err)
}).then ( abcMessage =>
console.log(abcMessage)
)
.then and .catch require a Promise to be constructed. You are not returning a promise. The promise callback (executor) takes two arguments, a resolver, and a rejecter. Depending on what happens in the code, you may need to call resolve if everything goes right, or reject if something goes wrong.
function abc() {
return new Promise(function(resolve, reject) {
reject(123)
});
};
abc()
.catch(err => {
console.log(err);
return err;
})
.then(abcMessage => {
console.log(abcMessage)
});
new Error("error in promise")

Categories

Resources