Uncaught exception onReject callback Promise - javascript

Since yesterday , I try to understand a behavior that I did not know about onReject Promise callback. In fact, I work with an API (return json data) and Superagent for make request. I have this class:
class Api
{
constructor(uri) {
...
}
// Simple GET HTTP Request
get(...) {
var url = this.buildUrl(...);
this.requestPending = request.get(url);
return new Promise((resolve, reject) => {
this.requestPending.end((err, res) => {
if (err) {
reject(res.body.error);
} else {
resolve(res.body);
}
});
});
}
}
What I do not understand is that:
reject(res.body.error);
throw an exception (res.body.error contains a simple string). Indeed, firebug display this error:
uncaught exception: ...
Could you explain this behavior ?
PS: I work with babel for transpile js.
Edit
I tested with when librairie but I have the same result. However, when I write:
reject(new Error("foo"));
The onReject callback is never call:
when.all([
api.get(...),
api.get(...)
]).then(data => {
console.log(data)
}, err => {
console.log(err);
})
and in the browser:
I continue my research.
Edit 2
Really sorry , I deserve to be whipped on the public square !!!. In fact, I had to change one file instead of two. Really, really sorry !!

I dont know whether it is silly or not,may be the scope for requestPending might be the problem.sorry if it sounds silly,
var url = this.buildUrl(...),self = this;
this.requestPending = request.get(url);
return new Promise((resolve, reject) => {
self.requestPending.end((err, res) => {
if (err) {
reject(res.body.error);
} else {
resolve(res.body);
}
});
});
}
}

Related

why i keep getting undefined when i console.log this function

Hello I'm a complete beginner in node js and I just learned about promises and I'm trying to using them in my code
but when I try to console.log this function I keep getting undefined and I don't know why
I will be very thankful if you help me
function weather(location) {
const request = require('request');
const errorMessage = 'Something went wrong. Please check you internet connection or the URL you provided.';
new Promise((resolve, reject) => {
const geoUrl = `https://api.mapbox.com/geocoding/v5/mapbox.places/
${location}.json?access_token=pk.eyJ1Ijoic3F1YXJlc2NyaXB0IiwiYSI6ImNrc3lwZmdtejFpdzQycHB1eTVpODNwdmYifQ.izw6cVMKDZme4KJwxHdxjw`;
request({
url: geoUrl,
json: true
}, (error, request) => {
if (error) {
reject(errorMessage)
} else {
resolve(`http://api.weatherstack.com/current?access_key=
c704f108fc10fbbdb15c384daff85a20&query=${request.body.features[0].center.reverse()}`)
}
})
}).then(url => {
request({
url: url,
json: true
}, (error, request) => {
if (error) {
return errorMessage
} else {
const currData = request.body.current;
return `${currData.weather_descriptions[0]}, It's currently ${currData.temperature} degrees out. There is a ${currData.humidity}% chance of rain.`;
}
});
}).catch(message => message)
};
console.log(weather('NYC'))
You need to return the promise..
return new Promise((resolve,reject)=>{
And then the console will log "Unresolved promise." Or something like that. If you want to wait for the promise to resolve, you need to use await or the then method:
weather('NYC').then(console.log)
You also need to make sure your promise is being resolved or rejected:
if (error){reject(errorMessage)}
else {
const currData=request.body.current;
resolve(`${currData.weather_descriptions[0]}, It's currently ${currData.temperature} degrees out. There is a ${currData.humidity}% chance of rain.`);
}
All these little errors would be easier to spot if your code was formatted properly.
Also, don't put your private access tokens in public forums.
You can find lots of tutorials on how promises work around the internet. Here's the MDN manual page.

Why is my Promise always hitting the catch() method?

I'm using the JavaScript Promise object with a then(), catch().
The console.log in the catch() method always runs, regardless of the response from the API ("STATUS_SUCCESS" or "STATUS_FAILED").
Is this normal behaviour in promises or is there a way to only hit the catch() method if the response has failed?
Updated with live example:
sendAccountDataToBackend(response) {
const { formData } = response;
const requestObj = {
url: 'http://localhost:3000/api/validate',
data: {
firstname: 'dummy_firstname',
lastname: 'dummy_lastname',
email: 'dummyemail'
}
};
let p = new Promise((resolve, reject) => {
account.Utils.globalAjaxRequest(requestObj, (success) => {
if(success.status === 'STATUS_SUCCESS') {
resolve();
console.log('resolved: ', p)
} else {
reject();
console.log('rejected: ', p);
}
});
})
p.then(() => {
console.log('Then: ', response);
}).catch(() => {
console.log('catch:', response);
})
}
You can find the exact cause of the thrown error by printing it.
Change your catch handler to look like this:
catch((e) => {
console.log('Catch', e);
})
In addition to "Catch" you will see a description of the error in the console.
I figured out what was causing the catch to fire thanks to #pfcodes suggestion. I was calling a function within the then() block which was failing. Once removed, it stayed inside then(). Silly mistake that was over looked! Thanks for your suggestions.
Regarding the question:
Is this normal behaviour in promises or is there a way to only hit the catch() method if the response has failed?
It is easy to demonstrate that the catch is only entered when the reject call is made.
function testPromise(shouldReject)
{
return new Promise((resolve, reject) => {
setTimeout(function(){
if(shouldReject) reject();
else resolve();
},1000);
});
}
function handlePromise(p, name){
p.then(() => {
console.log(name, 'Then');
}).catch(() => {
console.log(name, 'Catch');
})
}
var rejectPromise = testPromise(true);
var resolvePromise = testPromise(false);
handlePromise(rejectPromise,"reject");
handlePromise(resolvePromise,"resolve");
So, what this means is that in your code, for whatever reason (probably badly handled asynchronous ajax call) you're entering the else block.
Regarding your update, I would say that success.status is returning something other than "STATUS_SUCCESS" for the reasons demonstrated by the code above.
Try adding console.log(success) inside the ajax callback.
account.Utils.globalAjaxRequest(requestObj, (success) => {
console.log(success);
....

Am I chaining Promises correctly or committing a sin?

I have not worked with Javascript in a long time, so now promises are a new concept to me. I have some operations requiring more than one asynchronous call but which I want to treat as a transaction where steps do not execute if the step before failed. Currently I chain promises by nesting and I want to return a promise to the caller.
After reading the chaining section of Mozilla's Using Promises guide, I'm not sure if what I'm doing is correct or equivalent to the "callback pyramid of doom".
Is there a cleaner way to do this (besides chaining with a guard check in each then)? Am I right in my belief that in Mozilla's example it will execute each chained then even when there is an error?
myfunction(key) => {
return new Promise((outerResolve, outerReject) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}
}).then((resolve) => {
//Now the inner most item is resolved, we are working in the 'outer' shell
if (resolve.error) {
outerReject(resolve);
} else {
//No error, continue
new Promise((resolve, reject) => {
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}).then((resolve) => {
//finally return the result to the caller
if (resolve.error) {
outerReject(resolve);
} else {
outerResolve(resolve);
}
});
}
});
});
}
Subsequent then statements are not executed (until a catch) when an exception is thrown. Also, .then returns a Promise, so you don't need to create an additional, outer Promise.
Try this example:
var p = new Promise((resolve, reject) => {
console.log('first promise, resolves');
resolve();
})
.then(() => {
throw new Error('Something failed');
})
.then(() => {
console.log('then after the error');
return('result');
});
p.then(res => console.log('success: ' + res), err => console.log('error: ' + err));
You will not see "then after the error" in the console, because that happens after an exception is thrown. But if you comment the throw statement, you will get the result you expect in the Promise.
I am not sure I understand your example entirely, but I think it could be simplified like this:
myfunction(key) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: resolve(result);
});
}
}).then((previousData) => {
// keyBasedOnPreviousData is calculated based on previousData
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: return result;
});
});
}
It's a bit of a mess. This is my attempt at rewriting. A good thing to try to avoid is new Promise().
function chromeStorageGet(key) {
return new Promise( (res, rej) => {
chrome.storage.sync.get(key, result => {
if (chrome.runtime.lastError) {
rej(new Error(chrome.runtime.lastError.message))
} else {
res(result)
}
});
});
});
function myfunction(key) {
const item = cache.get(key) ? Promise.resolve(cache.get(key)) : chromeStorageGet(key);
return item.then( cacheResult => {
return chromeStorageGet(keyBasedOnPreviousData);
});
}
Why avoid new Promise()?
The reason for this is that you want to do every step with then(). If any error happened in any of the promises, every promise in the chain will fail and any subsequent then() will not get executed until there is a catch() handler.
Lots of promise based-code requires no error handlers, because promise-based functions always return promises and exceptions should flow all the back to the caller until there is something useful to be done with error handling.
Note that the exceptions to these 2 rules are in my chromeStorageGet function. A few notes here:
new Promise can be a quick and easy way to convert callback code to promise code.
It's usually a good idea to just create a little conversion layer for this callback-based code. If you need chrome.storage.sync in other places, maybe create a little utility that promisifies all its functions.
If there is only 1 'flow', you can just use a series of then() to complete the process, but sometimes you need to conditionally do other things. Just splitting up these complicated operations in a number of different functions can really help here.
But this:
const result = condition ? Promise.resolve() : Promise.reject();
Is almost always preferred to:
const result = new Promise( (res, rej) => {
if (condition) {
res();
} else {
rej();
}
}

How to get promise.response to return an API’s response?

TLDR: my promise.response needed to be called within both the API call and the promise.
I am attempting to get a return value from an API call via a Promise for a simple Express.js server.
This seems to be a topic of a lot of questions, but I have yet to successfully adapt an implementation to this case. I've also tried:
placing the API call within resolve()
async/wait implementations (willing to revisit)
Here's the basic structure of the code in question. There's a comment above the section where the trouble probably is.
Promise
const externalModule = require('<route to module>');
let promise = new Promise(function(resolve,reject) {
// This is probably where the problem is
let returnValue = externalModule.apiCall(parameters);
resolve(returnValue);
});
promise.then(function(returnValue) {
console.log(returnValue);
});
External Module
module.exports = {
apiCall: function(parameters) {
apiCall(
parameters,
function(err, response) {
if (err) {
console.error(err);
return;
} else {
console.log("success");
return response
}
}
)
}
};
If the code were working properly, we'd see two strings. One from inside the API call ("success") and another from it's return value. Because undefined is appearing before "success," we know that the resolve function has fired before the function above it has returned.
Logs from the Shell
> undefined
> "success"
You aren't providing a way to use the response from the api call. Convert that toa promise and then use it.
module.exports = {
apiCall: function(parameters) {
return new Promise((res, rej) => {
apiCall(
parameters,
function(err, response) {
if (err) {
rej(err);
} else {
res(response);
}
}
)
});
}
};
Then use it like so
let promise = externalModule.apiCall(parameters);

Conditionally call a promise (or not), but return either result to another promise

having trouble trying to write the following code in a way that doesn't involve nested promises.
function trickyFunction(queryOptions, data) {
return new Promise((resolve, reject) => {
if (data) {
resolve(data);
} else {
// ... a bunch of conditions to check and/or modify queryOptions. These checks and mods
// are vital but only required if data is not passed in. ...
if (anErrorHappensHere) {
reject('Oh no, an error happened');
}
somePromise(queryOptions).then((result) => {
resolve(result);
});
}
}).then((result) => {
criticalOperation1(result);
// the code here is long and shouldn't be duplicated
});
}
I really don't like the .then() chain after somePromise since it's inside the new Promise, but I really don't see a way around it. If I take the conditional out of a promise, then I'd have to duplicate the criticalOperation1 code, which isn't an option here. The conditional checks in the else block should only happen if data is not passed in. Making other functions is not permitted in my case, and using async/await is also not permitted in my case.
Does anyone have any ideas? I've worked with Promises for a bit but this one is stumping me.
I would just avoid using the new Promise syntax in this case and just start the promise chain early
function trickyFunction(queryOptions, data) {
return Promise.resolve()
.then( () => {
if (data) {
return Promise.resolve(data);
} else {
// ... a bunch of conditions to check and/or modify queryOptions. These checks and mods
// are vital but only required if data is not passed in. ...
if (anErrorHappensHere) {
// Could also just throw here
return Promise.reject('Oh no, an error happened');
}
return somePromise(queryOptions);
}
})
.then((result) => {
criticalOperation1(result);
// the code here is long and shouldn't be duplicated
});
}
function trickyFunction(queryOptions, data) {
return new Promise((resolve, reject) => {
if (anErrorHappensHere) {
reject('Oh no, an error happened');
}
resolve({data, queryOptions});
}).then((obj) => {
if(obj.data){
return Promise.resolve(obj.data);
} else {
return somePromise(obj.queryOptions)
}
}).then((result) => criticalOperation1(result));
.catch((err)=> console.log(err));
}

Categories

Resources