How to resolve promises and catch an error - javascript

I am trying to user webgazer.js where my code basically checks to see whether the webgazer is initialized and when it is initialized it resolves a promise which dispatches an action. This works however if for example there is no webcam I need to throw an error. The error in my code never gets called.
Here is my code
export function detectJsCamera() {
return async(dispatch) => {
dispatch({type: types.JS_DETECTING_CAMERA});
try {
await detectCamera();
await dispatch({type: types.JS_CAMERA_DETECTED});
} catch (error) {
await dispatch({type: types.CAMERA_DETECTION_FAILED, error: error.message});
throw error;
// this.props.history.push('/setup/positioning')
};
}
}
const detectCamera = () => new Promise((resolve, reject) => {
const checkIfReady = () => {
if (webgazer.isReady()) {
resolve('success');
} else {
console.log('called')
setTimeout(checkIfReady, 100);
}
}
setTimeout(checkIfReady,100);
});

You will need to reject in order to throw an exception like below
const detectCamera = () => new Promise((resolve, reject) => {
const checkIfReady = () => {
if (webgazer.isReady()) {
resolve('success');
} else {
console.log('called');
reject("some error");
}
}
setTimeout(checkIfReady,100);
});

You need to call reject() in your detectCamera method when your webgazer is not initialised then it would be caught in your catch block in detectJsCamera method.

Related

escape loop using an error from async function?

let me explain what I mean using an example
async function async_function(){
await new Promise(r=>setTimeout(r,3000));
throw 'task completed'
}
async function do_something_meanwhile() {
await new Promise(r => setTimeout(r, 500));
console.log(Math.floor(Math.random()*10));
}
(async ()=>{
try {
async_function(); //this returns an error after a while
while (...)
await do_something_meanwhile();
} catch (err) { console.log('exited with error:',err) }
console.log('moving on');
})();
I'm trying to run an async function and after it is complete immediately terminate the loop,
the best way I could think of (without any time delay) was to send an error
but it gives this error instead of moving on after it's done:
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: 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(). The promise rejected with the reason "task
completed".] {
code: 'ERR_UNHANDLED_REJECTION'
}
is there a way around this or a better to achieve the desired effect?
You can handle rejection by setting an error variable that you can check in the loop:
try {
let error;
async_function()
.catch(err => error = err);
while (...) {
if (error) {
throw error;
}
await do_something_meanwhile();
}
} catch (err) {
console.log('exited with error:',err)
}
If you need to proactively tell do_something_meanwhile to terminate as well, you could use an AbortController and pass its signal to do_something_meanwhile.
try {
let error;
const controller = new AbortController();
const { signal } = controller;
async_function()
.catch(err => {
error = err;
controller.abort();
});
while (...) {
if (error) {
throw error;
}
await do_something_meanwhile(signal);
}
} catch (err) {
console.log('exited with error:',err)
}
I think if I were doing that, I might subclass AbortController so I can put the error in it:
class AbortContollerWithError extends AbortController {
abort(error) {
this.error = error;
super.abort();
}
}
then:
try {
const controller = new AbortController();
const { signal } = controller;
async_function()
.catch(err => {
controller.abort(err);
});
while (...) {
if (signal.aborted) {
throw controller.error;
}
await do_something_meanwhile(signal);
}
} catch (err) {
console.log('exited with error:',err)
}
...or something along those lines.
You asked how you'd use the signal in do_something_meanwhile, and suggested in a comment that you're really using a timer in it. That's where the signal's abort event comes in handy, you can use that to settle the promise early:
async function do_something_meanwhile(signal) {
let cancelError = {};
try {
await new Promise((resolve, reject) => {
const timer = setTimeout(resolve, 500);
signal.addEventListener("abort", () => {
clearTimeout(timer);
cancelError = new Error();
reject(cancelError);
});
});
console.log(Math.floor(Math.random() * 10));
} catch (error) {
if (error === cancelError) {
// Probably do nothing
} else {
// Something else went wrong, re-throw
throw error;
}
}
}
Promise.all can run async_function and do_something_meanwhile in parallel mode.
While Promise/A doesn't have a cancel method, you can define a stopFlag, and check it in do_something_meanwhile function and the while loop.
let stopFlag = false
async function async_function() {
await new Promise(r=>setTimeout(r, 3000));
throw 'task completed'
}
async function do_something_meanwhile() {
await new Promise(r => setTimeout(r, 500));
if (!stopFlag) {
console.log(Math.floor(Math.random() * 10));
}
}
(async()=>{
try {
await Promise.all([
async_function().catch((err) => {
stopFlag = true
throw err
}), // this returns an error after a while
(async () => {
while (!stopFlag)
await do_something_meanwhile();
})()
])
} catch (err) {
console.log('exited with error:', err)
}
console.log('moving on');
})();

How to throw out of then-catch block?

I am currently figuring out how to throw an Exception out of a then catch block. I want to get into the catch that is inside the errorHandler() function.
const errorHandler = function () {
try {
thisFunctionReturnsAnError().then(response => {
console.log(response);
});
} catch (e) {
console.log(e); //How to trigger this?
}
};
const thisFunctionReturnsAnError = function () {
return3()
.then(value => {
throw new Error('This is the error message.');
})
.catch(err => {
//return Promise.reject('this will get rejected');
throw err;
//this one should somehow got to the catch that is located in the errorHandler() function. How to do this?
//I know that this 'err' will be in the next catch block that is written here. This is not what i want.
});
};
const return3 = async function () {
return 3;
};
errorHandler();
I searched a while on stackoverflow but nothing helped me. I am sure that this question got asked often but I could not find the answer, sorry for that.
EDIT:
added here another version of the code but it still does not work
const errorHandler = async function () {
try {
thisFunctionReturnsAnError()
.then(response => console.log(response))
.catch(err => console.log(err));
} catch (e) {
//console.log(e); //How to trigger this?
}
};
const thisFunctionReturnsAnError = function () {
return3()
.then(value => {
throw new Error('This is the error message.');
})
.catch(err => {
return Promise.reject(`Message is: ${err}`);
});
};
const return3 = async function () {
return 3;
};
errorHandler();
I will get the following error message:
Uncaught (in promise) Message is: Error: This is the error message.
Your code can't be executed, because "thisFunctionReturnsAnError" is not returning an Promise. That means that you can't call "then" on the return value.
thisFunctionReturnsAnError().then(response => { // will not work
Why not always use a promise?
const errorHandler = function () {
thisFunctionReturnsAnError()
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log('errorHandler: Handle the error.');
});
};
const thisFunctionReturnsAnError = function () {
return return_Three()
.then((value) => {
throw new Error('This is the error message.');
})
.catch((err) => {
//return Promise.reject('this will get rejected');
throw err;
//this one should somehow got to the catch that is located in the errorHandler() function. How to do this?
//I know that this 'err' will be in the next catch block that is written here. This is not what i want.
});
};
const return_Three = async function () {
return 3;
};
errorHandler();
/*****JUST ANOTHER SYNTAX*******/
const secondErrorHandler = async function () {
try {
await thisFunctionReturnsAnError();
} catch (error) {
console.log('secondErrorHandler: Handle the error.');
}
};
secondErrorHandler();
You cannot handle promise rejections with synchronous try/catch. Don't use it, use the promise .catch() method like in your thisFunctionReturnsAnError function.
You can handle promise rejections with try/catch when using async/await syntax (which you already do, albeit unnecessarily, in return3):
async function errorHandler() { /*
^^^^^ */
try {
const response = await thisFunctionReturnsAnError();
// ^^^^^
console.log(response);
} catch (e) {
console.log(e); // works
}
}

Break out of Async Function Within a Catch Block

I have the following function:
async myFunction() {
await this.somePromiseFunction().then(
() => alert('Promise Complete!'),
() => {
throw new Error('Error');
}
).catch(() => {
alert('End the Function Here');
});
alert('Do not get called if error caught above.');
await this.anotherPromiseFunction().then(
() => alert('Promise Complete!'),
() => {
throw new Error('Error');
}
).catch(() => {
alert('End the Function Here');
});
}
I would like it such that when an error is caught in the promise return handler that it ends the asynchronous function as I do not want it to continue in that case.
Instead of mixing await with .then(), just await each asynchronous function call directly in a try block and deal with the error appropriately.
If the asynchronous function returns a rejected promise, await will cause the rejection to throw from the try block and be caught, skipping the rest of the control flow inside the try.
const asyncFactory = label => async () => {
await new Promise(resolve => { setTimeout(resolve, 1000); });
if (Math.random() < 0.25) {
throw new Error(`${label} Error`);
}
console.log(`${label} Complete!`);
};
const somePromiseFunction = asyncFactory('somePromiseFunction');
const anotherPromiseFunction = asyncFactory('anotherPromiseFunction');
async function myFunction() {
try {
console.log('Start myFunction here');
await somePromiseFunction();
await anotherPromiseFunction();
} catch (error) {
console.log('Error caught:', error.message);
} finally {
console.log('End myFunction here');
}
}
myFunction();
You can actually achieve the equivalent without using async and await, and you don't need to nest your promises to do so:
const asyncFactory = label => () => {
return new Promise(resolve => {
setTimeout(resolve, 1000);
}).then(() => {
if (Math.random() < 0.25) {
throw new Error(`${label} Error`);
}
console.log(`${label} Complete!`);
});
};
const somePromiseFunction = asyncFactory('somePromiseFunction');
const anotherPromiseFunction = asyncFactory('anotherPromiseFunction');
const oneMorePromiseFunction = asyncFactory('oneMorePromiseFunction');
function myFunction() {
console.log('Start myFunction here');
return somePromiseFunction().then(() => {
return anotherPromiseFunction();
}).then(() => {
return oneMorePromiseFunction();
}).catch(error => {
console.log('Error caught:', error.message);
}).finally(() => {
console.log('End myFunction here');
});
}
myFunction();
Do note that Promise.prototype.finally() is actually part of ECMAScript 2018, so if the browser supports it natively, it will also already support async and await. However, it can be polyfilled while async and await cannot.

Can not return from a function

I have a function that looks like following
export const checkForAvailableAgent = (topicId, serviceUrl, serviceId) => {
const serviceInfo = new window.adiaLive.ServiceInfo({
topicId: topicId, // set here the topicId which you want listen for
OnError: e => {
// react to error message (optional)
console.log("error: ", e);
},
OnServiceStateChange: e => {
if (e.ConnectedAdvisers > 0) {
// there are advisers online for given topicId
console.log("studio available");
return true;
} else {
console.log("studio not available");
return false;
}
}
});
serviceInfo.connect(serviceUrl, serviceId);
};
however the return statements don't return anything when I use the function in the following manner
useEffect(() => {
const agent = checkForAvailableAgent(
`sales_${i18n.language}`,
"https://linktoserviceurl",
"serviceid"
);
// console.log("studio available is: ", agent);
}, []);
the console.log massages appear but the return statement is undefined.
any help would be appreciated.
You can not return from a callback function, as it is running asynchronously and you are not waiting for it to have a result ready.
You can however make the function itself async by returning a Promise instead of the actual result and wait until the Promise has a result ready (e.g. it is resolved):
export const checkForAvailableAgent = (topicId, serviceUrl, serviceId) => {
return new Promise((resolve, reject) => {
const serviceInfo = new window.adiaLive.ServiceInfo({
topicId: topicId, // set here the topicId which you want listen for
OnError: e => {
// react to error message (optional)
console.log("error: ", e);
reject(); // reject on failure
},
OnServiceStateChange: e => {
if (e.ConnectedAdvisers > 0) {
// there are advisers online for given topicId
console.log("studio available");
resolve(true); // resolve instead of return
} else {
console.log("studio not available");
resolve(false);
}
}
});
serviceInfo.connect(serviceUrl, serviceId);
})
};
useEffect(() => {
checkForAvailableAgent(
`sales_${i18n.language}`,
"https://linktoserviceurl",
"serviceid"
).then((agent) => { // then callback is called when the promise resolved
console.log("studio available is: ", agent);
}).catch(error => { // catch is called when promise got rejected
console.log('An error happened');
});
}, []);
The function servceInfo.OnServiceStateChange is a function into the object (seems to be an event).
I'd suggest declaring a variable on the checkForAvailableAgent like connected and change it's value when the event is called.
Then access it using checkForAvailableAgent.connected.
A version with async/await and try/catch
export const checkForAvailableAgent = (topicId, serviceUrl, serviceId) => {
return new Promise((resolve, reject) => {
const serviceInfo = new window.adiaLive.ServiceInfo({
topicId: topicId,
OnError: reject,
OnServiceStateChange: e => resolve(e.ConnectedAdvisers > 0)
});
serviceInfo.connect(serviceUrl, serviceId);
})
};
useEffect(() => {
(async () => {
try {
const isAvailable = await checkForAvailableAgent(
`sales_${i18n.language}`,
"https://linktoserviceurl",
"serviceid"
);
// console.log("Result", isAvailable)
} catch(e) {
console.error(e)
}
})()
// console.log("studio available is: ", agent);
}, []);
There are 2 possible reasons
you are not returning anything from checkForAvailableAgent.
After returning from the checkForAvailableAgent, it might be asynchronous function. You can use async & await.

Promises not handled through Redux

I'm trying to perform some actions once all my data are loaded but I have troubles with promises that are not handled properly.
export function waitForAll() {
return function (dispatch, getState) {
Promise.all([
dispatch(getCharacteristics()),
dispatch(getItems())]
).then(()=>{
let state = getState();
dispatch(update(state))
}).catch(function(err){
console.log(err);
});
}
}
And here are the 2 functions called for this promise :
export function getCharacteristics() {
return function (dispatch) {
axios.get('api/charac').then((response) =>
{
dispatch(fetchCharacteristics(response.data));
}).catch(error =>{
console.log(error);
});
}
}
And
export function getItems() {
return function (dispatch) {
axios.get('api/45897').then((response) =>
{
dispatch(fetchItems(response.data.equipements));
}).catch(error =>{
console.log(error);
});
}
}
My states are not updated, that means that my promises are not handled properly, I've initial state like [].
An alternative could be componentDidMount() in React to call that function but I'm not sure how to verify that BOTH states are loaded correctly (different components)
I can't figure out how I can make it work, any help would be welcome!
You aren't actually returning the promise. Arrange your code to return the promise (not just resolve it) and then you'll be able to leverage Promise.all
Example:
async function promise1 () {
const promise = await fetch('https://jsonplaceholder.typicode.com/todos/1');
return promise.json();
};
async function promise2 () {
const promise = await fetch('https://jsonplaceholder.typicode.com/todos/2');
return promise.json();
};
async function getAllPromises() {
const results = await Promise.all([promise1(), promise2()]);
console.log(results);
};
getAllPromises();
Basically, I think you can just return the axios.<httpverb>
Example (best guess as I won't be able to get your code to run):
export function waitForAll() {
return function (dispatch, getState) {
Promise.all([
dispatch(getCharacteristics()),
dispatch(getItems())]
).then(()=>{
let state = getState();
dispatch(update(state))
}).catch(function(err){
console.log(err);
});
}
}
export function getCharacteristics(dispatch) {
return new Promise ( (resolve, reject) {
axios.get('api/charac').then((response) =>
{
resolve(dispatch(fetchCharacteristics(response.data)));
}).catch(error =>{
reject(error);
console.log(error);
});
});
}
export function getItems(dispatch) {
return new Promise ((resolve, reject) {
axios.get('api/45897').then((response) =>
{
resolve(dispatch(fetchItems(response.data.equipements)));
}).catch(error =>{
reject(error);
console.log(error);
});
});
}

Categories