Reputation:
I am newbie to promises, I am trying to understand how do they work.
Here my questions at first:
When request is handled in a route function, does it wait for all promises, I mean that when I am using promise or callback it is a new scope and execution continues further.
If I keep a req/res objects for example in timer and then respond to user, what will user see ? A request will just be blocked until I explicitly send response ?
So I have encountered the following problems.
Here is my route.
router.post('book', authHandler.provideMiddleware(), (req, res) => {
bookManager.createBook(req.body, {
onSuccess: function (data) {
respondSuccess(res,HttpStatus.OK, {'data': data});
},
onError: function (message) {
respondError(res, HttpStatus.HTTP_STATUS.BAD_REQUEST, {'error': message});
}
});
});
Inside bookmanager I have the following
createBook(data, hook) {
let book = createBookFromRequest(data);
let verifyData = new Promise((resolve, reject) => {
let valid = checkBookData(book);
if(valid) {
resolve(book);
}
else {
reject("Invalid data");
}
});
let createBook = new Promise((resolve, reject) => {
book.save((err, result) => {
if (!err) {
reject("Error while saving");
}
else {
resolve(result);
}
});
});
verifyData
.then(() => {
return createBook;
})
.then((data) => {
hook.onSuccess(data);
})
.catch((error) => {
hook.onError(error);
});
}
My idea is to chain multiple functions and if any error occurred, call hook.onError method, otherwise call on success.
I have several problems here.
I have the following error
node:8753) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: Can't set headers after they are sent.
I want to use the approach like Rx (Reactive Extensions).
Could someone explain what is wrong and how do promises really work in this case ?
Upvotes: 2
Views: 1774
Reputation: 1074295
1. When request is handled in a route function, does it wait for all promises, I mean that when I am using promise or callback it is a new scope and execution continues further.
It waits for you to send a response via res
. You don't have to do that in response to the event, it's absolutely normal for it to be later, after an asynchronous process (like a promise resolution) completes.
2. If I keep a req/res objects for example in timer and then respond to user, what will user see ? A request will just be blocked until I explicitly send response ?
Yes.
I have several problems here.
1. When error is thrown, my book is still created.
You're always starting the process of creating the book, regardless of whether the data was verified as correct. new Promise
starts the work.
2. I have the following error
node:8753) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: Can't set headers after they are sent.
You're creating a promise and storing it in createBook
, and never handling rejections of that promise if verifyData
rejects. So you get an unhandled promise rejection.
You can get rid of the entire new Promise
around saving the book, and just put it in the verifyData
chain; see comments:
createBook(data, hook) {
let book = createBookFromRequest(data);
let verifyData = new Promise((resolve, reject) => {
let valid = checkBookData(book);
if (valid) {
resolve(book);
}
else {
reject("Invalid data");
}
});
verifyData
.then(() => book.save()) // The chain takes on the state of the promise
// returned by `book.save`
.then(data => {
hook.onSuccess(data);
})
.catch((error) => {
hook.onError(error);
});
}
In that, I'm assuming createBookFromRequest
and checkBookData
are both synchronous processes, as that's how you're using them.
And actually, given that's the case, I don't see any need for the promise you're creating to verify the data. So it could be simpler:
createBook(data, hook) {
let book = createBookFromRequest(data);
if (checkBookData(book)) {
book.save()
.then(_ => hook.onSuccess(data))
.catch(error => hook.onError(error));
} else {
hook.onError("Invalid data");
}
}
Upvotes: 3