named promise chainy for normal promises that handle events - javascript

I am trying to create a named promise chain. I am not sure of how to achieve this. The goal is following:
function multiplepromises() {
var prom = function (resolve, reject) {
var lifecycleeventone = new someEvent();
var lifecycleeventtwo = new someEvent();
var lifecycleeventthree = new someEvent();
var lifecycleeventfour = new someEvent();
var lifecycleeventfive = new someEvent();
lifecycleeventone.on(function () {
try {
resolve("eventone")
} catch {
reject("eventone")
}
})
lifecycleeventtwo.on(function () {
try {
resolve("eventtwo")
} catch {
reject("eventtwo")
}
})
lifecycleeventthree.on(function () {
try {
resolve("eventthree")
} catch {
reject("eventthree")
}
})
lifecycleeventfour.on(function () {
try {
resolve("eventfour")
} catch {
reject("eventfour")
}
})
lifecycleeventfive.on(function () {
try {
resolve("eventfive")
} catch {
reject("eventfive")
}
})
maineventlikefinallySOcalledalways.on(function(){
try {
resolve("maineventlikefinallySOcalledalways")
} catch {
reject("maineventlikefinallySOcalledalways")
}
})
}
return prom
}
multiplepromises()
.onlifecycleeventoneAsProm((result)=> result) //eventone promise resolve
.onlifecycleeventoneerrorAsProm((error)=> error) //eventone
.onlifecycleeventtwoAsProm((result)=> result) //eventtwo promise resolve
.onlifecycleeventtwoerrorAsProm((error)=> error) //eventtwo
.onlifecycleeventthreeAsProm((result)=> result) //eventthree promise resolve
.onlifecycleeventthreeerrorAsProm((error)=> error) //eventthree
.onlifecycleeventfourAsProm((result)=> result) //eventfour promise resolve
.onlifecycleeventfourerrorAsProm((error)=> error) //eventfour
.onlifecycleeventfiveAsProm((result)=> result) // eventfive promise resolve
.onlifecycleeventfiveerrorAsProm((error)=> error) //eventfive
.then((result)=> result) // maineventlikefinallySOcalledalways promise resolve
.error((error)=> error) // maineventlikefinallySOcalledalways promise reject
multiplepromises()
.onlifecycleeventoneAsProm((result)=> result) //eventone promise resolve
.onlifecycleeventoneerrorAsProm((error)=> error) //eventone
.onlifecycleeventtwoAsProm((result)=> result) //eventtwo promise resolve
.onlifecycleeventtwoerrorAsProm((error)=> error) //eventtwo
.onlifecycleeventthreeAsProm((result)=> console.log("test"))
// lifecycleeventthree promise reject stops here and
// doesnt continue to .then/.error since there was no return from this lifecycle event(promise)
I have read this and this doesnt solve the purpose completely.
Handling multiple catches in promise chain and https://javascript.info/promise-chaining
Dont want to use Rx and want to keep to vanilla js

You can‘t achieve something like that with Promises.
Instead you can make a function that returns an object with event registrar functions, which return again the object.
Here is a simple example:
function test() {
return new (function() {
this.eh = {};
this.on = (event, handler) => {
this.eh[event] = handler;
return this;
}
this.call = (event, ...args) => {
if (typeof this.eh[event] === 'function') {
this.eh[event](...args);
}
}
Promise.resolve().then(() => {
// Do your stuff...
// Example:
this.call('msg', 'This is a message.');
setTimeout(() => {
this.call('some-event', 'This is some event data.');
this.call('error', 'This is an error.');
}, 1000);
});
})()
}
test()
.on('msg', (msg) => console.log(`Message: ${msg}`))
.on('some-event', (data) => console.log(`Some event: ${data}`))
.on('error', (err) => console.log(`Error: ${err}`))
I hope that‘s what you were up to.
Edit:
Here's another attempt: https://jsfiddle.net/bg7oyxau/

Related

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
}
}

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.

How to resolve promises and catch an error

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.

Wrapping Auth0's parseHash function in a Promise

auth0.js has a function that's used to parse the URL hash fragment and extract the authentication result therefrom. I'm wrapping this function within one called loadSession as follows:
public loadSession(): void {
this.auth0.parseHash((err, authResult) => {
if (authResult) {
window.location.hash = '';
localStorage.setItem('token', authResult.accessToken);
// TODO (1)
} else if (err) {
// TODO (2)
}
});
}
As seen above, parseHash takes a callback function as an argument and I cannot control that. I would like loadSession to return a Promise that would be resolved at // TODO (1) and rejected at // TODO (2) above. This way I can do obj.loadSession().then(() => { // do something if successful }).catch((err) => { // raise error if not })
Simply wrap it inside a promise:
public loadSession() {
return new Promise((resolve, reject) => {
this.auth0.parseHash((err, authResult) => {
if(authResult) {
window.location.hash = '';
localStorage.setItem('token', authResult.accessToken);
resolve(authResult);
} else if (err) {
reject(err);
}
});
});
}
You can pretty much pass any callback function to a function that returns a promise given:
The callback is the last argument
The callback function takes error as it's first argument
Here is an example:
const asPromise =
(context) =>
(fn) =>
(args) =>
new Promise(
(resolve,reject) =>
fn.apply(
context,
(args||[]).concat(
function(){
if(arguments[0]){
reject(arguments[0]);return;
}
resolve(Array.from(arguments).slice(1));
}
)
)
);
// to apply parseHash on auth0
public loadSession(): Promise {
return asPromise(this.auth0)(this.auth0.parseHash)()
.then(
([authResult])=>{
if (authResult) {
window.location.hash = '';
localStorage.setItem('token', authResult.accessToken);
//whatever you return here is the resolve
return authResult;
}
//just throw in a promise handler will return a rejected promise
// this is only for native promises, some libraries don't behave
// according to spec so you should test your promise polyfil if supporting IE
throw "Promise resolved but got no authResult";
}
)
}
public loadSession(): Promise {
return new Promise((resolve, reject) => {
this.auth0.parseHash((err, authResult) => {
if (authResult) {
window.location.hash = '';
localStorage.setItem('token', authResult.accessToken);
// TODO (1)
// resolve(something)
} else if (err) {
// TODO (2)
// reject(something)
}
});
}
For more information about using Promise API, you can visit MDN Docs
Or you can use a tiny library that does that for you: promisify-auth0 on GitHub, promisify-auth0 on npmjs.org.
Now updated to version 9.5.1.

How to .catch a Promise.reject

I have a helper function for using fetch with CouchDB which ends as:
...
return fetch(...)
.then(resp => resp.ok ? resp.json() : Promise.reject(resp))
.then(json => json.error ? Promise.reject(json) : json)
and when I use it elsewhere, I was under the impression that I could .catch those explicit rejections:
above_function(its_options)
.then(do_something)
.catch(err => do_something_with_the_json_error_rejection_or_resp_not_ok_rejection_or_the_above(err))
but alas, I can't seem to be able to get a hold of the rejections.
The specific error I'm after is a HTTP 401 response.
What gives?
(Please note that there are implicit ES6 return's in the .thens)
function test() {
return new Promise((resolve, reject) => {
return reject('rejected')
})
}
test().then(function() {
//here when you resolve
})
.catch(function(rej) {
//here when you reject the promise
console.log(rej);
});
Make sure every call to a then() returns a value.
For e.g.
var url = 'https://www.google.co.in';
var options = {};
var resolves = Promise.resolve();
resolves.then(() => {
console.log('Resolved first promise');
var fetchPromise = fetch(url, options);
fetchPromise.then(() => {
console.log('Completed fetch');
});
})
.catch(error => {
console.log('Error', error);
});
Notice the console shows an uncaught exception. However, if you returned the inner promise (or any other value, which ends up turning into a promise via resolve), you end up flattening the promise so exception bubble up.
var url = 'https://www.google.co.in';
var options = {};
var resolves = Promise.resolve();
resolves.then(() => {
console.log('Resolved first promise');
var fetchPromise = fetch(url, options);
return fetchPromise.then(() => {
console.log('Completed fetch');
});
})
.catch(error => {
console.log('Error', error);
});
Notice the exception bubbles up to the outer promise. Hope this clears up things a little bit.
Why not wrap it in a try / catch block
// define a failing promise
const test = ()=> new Promise((resolve, reject) => reject('rejected'));
// using an immediately executing function to call an async block
(async ()=> {
try {
await test(); // => this will throw an error
} catch (er) {
console.log(er); // 'rejected'
}
})();
Promise rejections fall to the second param of the then function.
function test() {
return new Promise((resolve, reject) => {
return reject('rejected')
})
}
test().then(function() {
//here when you resolve
}, function(rej) {
//here when you reject the promise
console.log(rej)
})

Categories