Add reject/resolve to catch/success - javascript

I use the following code and I wonder for best practise usage if I should add reject to
this promise inside the catch?
run: function (req, res) {
if (req) {
return this._un(req).then(function() {
return proce.restart().then(function() {
return res.status(200).end("sucess");
//Here should I use reslove
});
}).catch(function(err) {
return res.status(500).send("error: " + err);
//Here should I use reject???
});
}
else {
return new Promise(function(resolve, reject) {
reject("No application content found");
});
}
}
};

You don't "add reject" to a promise. A promise is either unsettled, or settled (resolved/rejected).
If req is provided, your code currently returns a promise that will be resolved with the return value of end (if the restart was successful) or the return value of send (if it wasn't), which I believe in both cases is the response object itself (res).
If you want the caller to be aware of whether the restart was successful, then yes, you want to reject the promise instead; with ES2015 promises you can do that by throwing in catch and I assume Bluebird is similar:
.catch(function(err) {
res.status(500).send("error: " + err);
throw err; // Or `throw new Error(err);`, it depends on what `err` is and your convention
})
...or by using Bluebird's Promise.reject (which is also ES2015-compatible):
.catch(function(err) {
res.status(500).send("error: " + err);
return Promise.reject(err);
})
If you don't want the caller to be aware of whether the restart was successful, then don't.

Related

Promise resolves before forEach loop completes

I'm building my first CRUD (library) application and recently learned about promises as a means to avoid deeply-nested callbacks. I'm attempting to seed my DB with some data each time the server starts, but I seem to be missing something conceptually.
I have four objects in a bookData array that I want to iterate over and save to the DB using Mongoose:
function seedBooks() {
return new Promise(function(resolve,reject){
bookData.forEach(function(seed){
Book.create(seed, function(err, newBook){
if(err) {
reject(err);
}
});
});
resolve();
});
}
This function is one of a few that I am attempting to chain together, which is why I'm using promises. But I'm finding that seedBooks() resolves with anywhere between 1 and 4 of the sample books created,
function seedDB() {
removeAllBooks()
.then(function(){
return removeAllUsers();
})
.then(function(){
return seedUsers();
})
.then(function(){
return seedBooks();
})
.then(function(){
return seedBookInstances();
});
}
Am I understanding or using promises & resolve incorrectly? Any help is appreciated. Thanks!
Edit: The below explains why your code is not working and advice for, in general, how to convert non-promise code to promises. Since Mongoose produces promises, however, you should be using those instead of using new Promise. See Olegzandr's answer regarding that.
The promise is resolving immediately because you are calling resolve() immediately.
The rule of thumb when converting non-promises to promises is to promisify the smallest part of the non-promise code. In this case, it means promisifying the code to save a single item. If you do that, the collect place to call resolve() becomes clear:
function seedBook(seed) {
return new Promise(function (resolve, reject) {
Book.create(seed, function (err, newBook) {
if (err) { reject(err); } else { resolve(newBook); }
});
});
}
function seedBooks() {
return Promise.all(bookData.map(seedBook));
}
This also has the benefit of allowing you to access the returned newBooks, should you want to.
If you are using Mongoose, you can just do this:
const saveBooks = function(books) {
return books.map(function(seed) {
return Book.create(seed); // returns a promise
});
});
}
return Promise.all(saveBooks(books)).then(function(){
// all books are saved
});
You are resolving your Promise synchronously, right after you started your forEached requests, which are async. You may try the following approach instead:
function seedBooks() {
return new Promise(function(resolve,reject){
var count = 0, length = bookData.length;
bookData.forEach(function(seed){
Book.create(seed, function(err, newBook){
if(err) {
reject(err);
return;
}
if(count++ >= length ) {
resolve();
}
});
});
});
}
Here the Promise is being resolved only after all async requests are done.
Another option would be just to use Promise.all. In that approach you need to promisify all your requests in the loop, return an array of Promises and then call Promise.all(_seedBooks()).then(), where _seedBook returns an array of Promises:
function _seedBooks() {
return bookData.map(function(seed) {
return new Promise(function(resolve, reject) {
Book.create(seed, function(err, newBook) {
if(err) {
reject(err);
return;
}
resolve(newBook);
});
});
});
}
Promise.all(_seedBooks())
.then(function(result) { /* result is the array of newBook objects */ })
.catch(function(error) { /* error is the first rejected err */ })

Break out of an array of Promises while in .settle() (or equivalent)

We're currently using bluebird v2.9.8, unable to upgrade to v3 for compatibility (for now, but that might not have a solution either).
We've made use of .settle() in the past, but we've hit a case where we have a set of users, mapped to promises, that we need to confirm whether a specific field is true.
If there's a single case of false, then there's no need to continue. If they were all true that would mean we had executed all promises.
Promise.settle() will execute all, waiting until all are complete.
Again, the goal is to break as soon as we get a false.
Turns out an additional piece of the code was calling an additional Promise to get more info from the db. So, rewritten to use Promise.all():
var accessPromises = users.map(function (user) {
return new Promise(function(resolve, reject) {
if (user.userId == matchingUserId) {
return resolve(true);
} else if (user.type && user.type == matchingType) {
return resolve(true);
} else {
// See if this user is one of your connections
DB.getAdditionalUserInfo()
.then(function (additionalUserInfo) {
if (additionalUserInfo.a == user.userId)
return resolve(true);
else
return reject(false);
})
.catch(function (err) {
return reject(false);
});
}
});
});
Promise.all(accessPromises).then(function (accessResults) {
if (accessResults.every(result => result)
res.ok();
else
res.notFound();
})
.catch(function (err) {
res.notFound();
});
This does allow us to break after the 1st rejection, but any of the additional DB calls that were already started complete anyway.
This will work, and allow us to get the response back to the client faster, but still leaves a bit of wasted processing.
Use Promise.all() instead of Promise.settle().
Promise.all() will finish when the first promise it is passed rejects and will not wait for the rest. So, you can test your condition and then reject and then Promise.all() will also reject immediately.
Promise.settle(), on the other hand, will wait until all requests finish, regardless of outcome.
If you showed some representative code, we could help you much more specifically.
Here's a made up example:
function getUser(name) {
// code that returns a promise whose fulfilled value is a user object
}
function getUserTestField(name) {
return getUser(name).then(function(user) {
if (!user.someField) {
return Promise.reject({status: false});
} else {
return user;
}
}, function(err) {
return Promise.reject({errCode: err});
});
}
var promises = ["bob", "ted", "alice"].map(function(name) {
return getUserTestField(name);
});
Promise.all(promises).then(function(users) {
// all users had field set to true
}, function(err) {
if (err.status === false) {
// at least one user has the field set to false
} else {
// some other type of error here
console.log(err.errCode);
}
});

chaining promise (bluebird)

I am using nodeJs and bluebird. i have methode to check for parameters validity, so i create a module where i have (see code below) and all of them are promises.
exports.validateSpeciality = validateSpeciality;
exports.validateGovernorate = validateGovernorate;
exports.validateCities = validateCities;
In my controller (see code below) i always get the first promise result in the then containing "res.send(results)"
validator
.validateSpeciality(speciality)
.then(validator.validateGovernorate(governorate))
.then(validator.validateCities(governorate, cities))
.then(Doctor.searchBySpecialityAndByCities(speciality, cities))
.then(function (results) {
console.log(results);
res.send(results);
})
.catch(function (error) {
console.log(error);
res.status(400).send(error);
})
Can someone explain to me why it is not working in this way? even if one of the promise is rejected it always execute the last then and don't go to catch.
Currently in your Promise chain, you don't use the results of the previous function calls. You run the next promise, when the previous was not resolved. So, even one of the functions: validateGovernorate, validateCities, searchBySpecialityAndByCities rejected with error, the final then will be called anycase.
To fix that, run the next function, when the previous promise is resolved:
validator
.validateSpeciality(speciality)
.then(function() {
return validator.validateGovernorate(governorate);
})
.then(function() {
return validator.validateCities(governorate, cities);
});
.then(function() {
return Doctor.searchBySpecialityAndByCities(speciality, cities);
})
.then(function(results) {
console.log(results);
res.send(results);
})
.catch(function (error) {
console.log(error);
res.status(400).send(error);
});
Also, check that you haven't catch blocks in all the functions: validateGovernorate, validateCities, searchBySpecialityAndByCities. And if you have throw an error there or reject with error.
Check this article there is very good desribed how promises work.

JavaScript Promises - reject vs. throw

I have read several articles on this subject, but it is still not clear to me if there is a difference between Promise.reject vs. throwing an error. For example,
Using Promise.reject
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
return Promise.reject(new PermissionDenied());
}
});
Using throw
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
throw new PermissionDenied();
}
});
My preference is to use throw simply because it is shorter, but was wondering if there is any advantage of one over the other.
There is no advantage of using one vs the other, but, there is a specific case where throw won't work. However, those cases can be fixed.
Any time you are inside of a promise callback, you can use throw. However, if you're in any other asynchronous callback, you must use reject.
For example, this won't trigger the catch:
new Promise(function() {
setTimeout(function() {
throw 'or nah';
// return Promise.reject('or nah'); also won't work
}, 1000);
}).catch(function(e) {
console.log(e); // doesn't happen
});
Instead you're left with an unresolved promise and an uncaught exception. That is a case where you would want to instead use reject. However, you could fix this in two ways.
by using the original Promise's reject function inside the timeout:
new Promise(function(resolve, reject) {
setTimeout(function() {
reject('or nah');
}, 1000);
}).catch(function(e) {
console.log(e); // works!
});
by promisifying the timeout:
function timeout(duration) { // Thanks joews
return new Promise(function(resolve) {
setTimeout(resolve, duration);
});
}
timeout(1000).then(function() {
throw 'worky!';
// return Promise.reject('worky'); also works
}).catch(function(e) {
console.log(e); // 'worky!'
});
Another important fact is that reject() DOES NOT terminate control flow like a return statement does. In contrast throw does terminate control flow.
Example:
new Promise((resolve, reject) => {
throw "err";
console.log("NEVER REACHED");
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
vs
new Promise((resolve, reject) => {
reject(); // resolve() behaves similarly
console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
Yes, the biggest difference is that reject is a callback function that gets carried out after the promise is rejected, whereas throw cannot be used asynchronously. If you chose to use reject, your code will continue to run normally in asynchronous fashion whereas throw will prioritize completing the resolver function (this function will run immediately).
An example I've seen that helped clarify the issue for me was that you could set a Timeout function with reject, for example:
new Promise((resolve, reject) => {
setTimeout(()=>{reject('err msg');console.log('finished')}, 1000);
return resolve('ret val')
})
.then((o) => console.log("RESOLVED", o))
.catch((o) => console.log("REJECTED", o));
The above could would not be possible to write with throw.
try{
new Promise((resolve, reject) => {
setTimeout(()=>{throw new Error('err msg')}, 1000);
return resolve('ret val')
})
.then((o) => console.log("RESOLVED", o))
.catch((o) => console.log("REJECTED", o));
}catch(o){
console.log("IGNORED", o)
}
In the OP's small example the difference in indistinguishable but when dealing with more complicated asynchronous concept the difference between the two can be drastic.
TLDR: A function is hard to use when it sometimes returns a promise and sometimes throws an exception. When writing an async function, prefer to signal failure by returning a rejected promise
Your particular example obfuscates some important distinctions between them:
Because you are error handling inside a promise chain, thrown exceptions get automatically converted to rejected promises. This may explain why they seem to be interchangeable - they are not.
Consider the situation below:
checkCredentials = () => {
let idToken = localStorage.getItem('some token');
if ( idToken ) {
return fetch(`https://someValidateEndpoint`, {
headers: {
Authorization: `Bearer ${idToken}`
}
})
} else {
throw new Error('No Token Found In Local Storage')
}
}
This would be an anti-pattern because you would then need to support both async and sync error cases. It might look something like:
try {
function onFulfilled() { ... do the rest of your logic }
function onRejected() { // handle async failure - like network timeout }
checkCredentials(x).then(onFulfilled, onRejected);
} catch (e) {
// Error('No Token Found In Local Storage')
// handle synchronous failure
}
Not good and here is exactly where Promise.reject ( available in the global scope ) comes to the rescue and effectively differentiates itself from throw. The refactor now becomes:
checkCredentials = () => {
let idToken = localStorage.getItem('some_token');
if (!idToken) {
return Promise.reject('No Token Found In Local Storage')
}
return fetch(`https://someValidateEndpoint`, {
headers: {
Authorization: `Bearer ${idToken}`
}
})
}
This now lets you use just one catch() for network failures and the synchronous error check for lack of tokens:
checkCredentials()
.catch((error) => if ( error == 'No Token' ) {
// do no token modal
} else if ( error === 400 ) {
// do not authorized modal. etc.
}
There's one difference — which shouldn't matter — that the other answers haven't touched on, so:
If the fulfillment handler passed to then throws, the promise returned by that call to then is rejected with what was thrown.
If it returns a rejected promise, the promise returned by the call to then is resolved to that promise (and will ultimately be rejected, since the promise it's resolved to is rejected), which may introduce one extra async "tick" (one more loop in the microtask queue, to put it in browser terms).
Any code that relies on that difference is fundamentally broken, though. :-) It shouldn't be that sensitive to the timing of the promise settlement.
Here's an example:
function usingThrow(val) {
return Promise.resolve(val)
.then(v => {
if (v !== 42) {
throw new Error(`${v} is not 42!`);
}
return v;
});
}
function usingReject(val) {
return Promise.resolve(val)
.then(v => {
if (v !== 42) {
return Promise.reject(new Error(`${v} is not 42!`));
}
return v;
});
}
// The rejection handler on this chain may be called **after** the
// rejection handler on the following chain
usingReject(1)
.then(v => console.log(v))
.catch(e => console.error("Error from usingReject:", e.message));
// The rejection handler on this chain may be called **before** the
// rejection handler on the preceding chain
usingThrow(2)
.then(v => console.log(v))
.catch(e => console.error("Error from usingThrow:", e.message));
If you run that, as of this writing you get:
Error from usingThrow: 2 is not 42!
Error from usingReject: 1 is not 42!
Note the order.
Compare that to the same chains but both using usingThrow:
function usingThrow(val) {
return Promise.resolve(val)
.then(v => {
if (v !== 42) {
throw new Error(`${v} is not 42!`);
}
return v;
});
}
usingThrow(1)
.then(v => console.log(v))
.catch(e => console.error("Error from usingThrow:", e.message));
usingThrow(2)
.then(v => console.log(v))
.catch(e => console.error("Error from usingThrow:", e.message));
which shows that the rejection handlers ran in the other order:
Error from usingThrow: 1 is not 42!
Error from usingThrow: 2 is not 42!
I said "may" above because there's been some work in other areas that removed this unnecessary extra tick in other similar situations if all of the promises involved are native promises (not just thenables). (Specifically: In an async function, return await x originally introduced an extra async tick vs. return x while being otherwise identical; ES2020 changed it so that if x is a native promise, the extra tick is removed where there is no other difference.)
Again, any code that's that sensitive to the timing of the settlement of a promise is already broken. So really it doesn't/shouldn't matter.
In practical terms, as other answers have mentioned:
As Kevin B pointed out, throw won't work if you're in a callback to some other function you've used within your fulfillment handler — this is the biggie
As lukyer pointed out, throw abruptly terminates the function, which can be useful (but you're using return in your example, which does the same thing)
As Vencator pointed out, you can't use throw in a conditional expression (? :), at least not for now
Other than that, it's mostly a matter of style/preference, so as with most of those, agree with your team what you'll do (or that you don't care either way), and be consistent.
An example to try out. Just change isVersionThrow to false to use reject instead of throw.
const isVersionThrow = true
class TestClass {
async testFunction () {
if (isVersionThrow) {
console.log('Throw version')
throw new Error('Fail!')
} else {
console.log('Reject version')
return new Promise((resolve, reject) => {
reject(new Error('Fail!'))
})
}
}
}
const test = async () => {
const test = new TestClass()
try {
var response = await test.testFunction()
return response
} catch (error) {
console.log('ERROR RETURNED')
throw error
}
}
test()
.then(result => {
console.log('result: ' + result)
})
.catch(error => {
console.log('error: ' + error)
})
The difference is ternary operator
You can use
return condition ? someData : Promise.reject(new Error('not OK'))
You can't use
return condition ? someData : throw new Error('not OK')

Promise code are read twice

I use the following code to read json file and return a promise
I've two questions
return globAsync("folder/*.json").catch(function (err) {
throw new Error("Error read: " + err);
}).map(function (file) {
return fs.readFileAsync(file, 'utf8')
.then(function (res) {
console.log("test");
return JSON.parse(res);
},
function (err) {
throw new Error("Error :" + err);
}).then(function () {
console.log("test2");
});
});
I use the console log and I see that the console is printed twice
test
test
test2
test2
why its happening and how to avoid it ?
In the place I've put console.log("test2"); I need to invoke event
that the json parse is finished and still return outside the json object (to the caller), when I add the last then it doesn't work(the returned object is undefined),any idea how to do that right?
UPDATE I try like following which it doesn't work...
return globAsync("folder/*.json").catch(function (err) {
throw new Error("Error read: " + err);
}).map(function (file) {
return fs.readFileAsync(file, 'utf8')
.then(function (res) {
console.log("test");
JSON.parse(res); //data parse
}.catch(function (err) {
throw new Error("Error :" + err);
}
).then(function (data) {
obj.emit('ready');
return data;
}))
});
}
UPDATE2 I was able to solve it by simply add new return JSON.parse(res);
Now how should I solve the first issue which method called twice
Like #jaromandaX said, you probably got two *.json files. Try to print out the file name instead and it should become more obvious. In that case, .map is expected to be called twice, once for each file. Otherwise you aren't gonna be able to read and parse two files together.
If you want to get it to converge to a single point after all file reads and parses are complete, then you need to chain another .then after .map. eg.
return globAsync("folder/*.json")
.map(function(file) {
...
})
.then(function() {
obj.emit('ready');
});
EDIT To answer your question in comment. There are a few things you should keep in mind.
Throwing Error inside the promise chain will get caught by the promise and send it into the rejection flow. You may still throw an error if you are interested in getting custom error type or printing stack trace in a desirable way. But most people prefer return Promise.reject(error).
Any rejection in .map will send the promise chain into rejection flow.
Inside the rejection chain, if you want to continue down the rejection flow. You need to return Promise.reject(error), otherwise if you don't return a reject object, you can bring it back into resolve flow.
If you want to want to handle each error individually, you can do something like this:
return globAsync("folder/*.json")
.catch(function(error) {
// TODO: Handle error
return Promise.reject(error);
})
.map(function(file) {
return fs.readFileAsync(file, 'utf8')
.catch(function(error) {
// TODO: Handle error
return Promise.reject(error);
})
.then(function(res) {
return JSON.parse(res);
});
})
.then(function() {
obj.emit('ready');
});
If you want to handle once for glob and once for file read, then you have to get a bit more creative.
return globAsync("folder/*.json")
.catch(function(error) {
// TODO: Handle error
return Promise.reject(error);
})
.then(function(files) {
return Promise.resolve(files)
.map(function(file) {
return fs.readFileAsync(file, 'utf8');
})
.catch(function(error) {
// TODO: Handle error once for any read error
return Promise.reject(error);
})
.map(function(res) {
// Judging by your original code, you are not handling
// parser error, so I wrote this code to behave equivalent
// to your original. Otherwise chain parse immediate after
// readFileAsync.
return JSON.parse(res);
});
})
.then(function() {
obj.emit('ready');
});

Categories

Resources