user4510167
user4510167

Reputation:

Using promises with Node JS express

I am newbie to promises, I am trying to understand how do they work.

Here my questions at first:

  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.

  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 ?

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.

  1. When error is thrown, my book is still created.
  2. 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

Answers (1)

T.J. Crowder
T.J. Crowder

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

Related Questions