Home > Software design >  Understanding execution flow in asynchronous functions
Understanding execution flow in asynchronous functions

Time:07-30

consider the following code. It was grabbed from here.

return new Promise((resolve, reject) => {
    const req = https.request(URL, options, res => {
        let rawData = '';

        res.on('data', chunk => {
            rawData  = chunk;
        });

        res.on('end', () => {
            resolve(rawData);
        });
    });

    req.on('error', err => {
        reject(new Error(err));
    });

    req.end();
});

I think I've got a pretty clear understanding of how this works.

When I call the function that contains this code, a promise will be returned.

Inside this function when https.request is executed, I am passing in a callback function. In side the https.request code, it will callback this function to process certain events. In this case, it looks like to receive data, or to catch the end of the connection. If the end of the connection is detected, the parent promise will be fulfilled and the data will be returned to the calling application.

However, later in this function, I am looking at the returned req object and detecting an error event to reject the parent promise. And finally, the end method of https.request is called to close the connection.

My question is this, when does the code after the https.request execute? That is, the req.on('error'...) and the req.end().

My understanding suggests a couple of different things...

  1. The https.request returns a promise and then the req.on('error'...) and req.end() code is executed. But, if that were true, then it appears it would potentially end the request before it had time to complete the request or process any data.

or

  1. The https.request blocks execution and a promise is returned to the caller. The req.on('error'...) and req.end() does not execute until the https.request resolves. This would be akin to using await on the https.request? But, if that were the case, when would I write a stream to the req object to upload a file on a POST request? I'm assuming right after the req.on('error'...) and before the req.end()? However, if I did that, how would I get a response from the server after the stream completes?

Basically, I would like to understand the program execution flow in the code, along with any explanation why based on the async/promise functionality. I specifically don't understand if https.request returns a promise in async mode or blocks code execution in await mode based on the fact a callback function was provided.

CodePudding user response:

end doesn't close the connection. It actually starts sending it. The delegate passed to the Promise constructor is executed immediately (before the promise is returned to your code).

The delegate passed to request is executed when (and if) the response arrives.

CodePudding user response:

I am passing in a callback function. In side the https.request code, it will callback this function to process certain events.

No. The callback you're passing is called asychronously (not sure if that counts as "within" in your book) when a response is received. That response is a stream on which then the data and end event listeners are installed (which again will be invoked asynchronously).

The docs say "The callback is invoked with a single argument that is an instance of http.IncomingMessage." or here "The optional callback parameter will be added as a one-time listener for the 'response' event."

(Admittedly I needed to link the http docs instead of the https ones, since those only document the difference from http but work the same otherwise)

The https.request returns a promise

No it doesn't. It returns without blocking, no promises involved.

The docs say: "https.request() returns an instance of the http.ClientRequest class. The ClientRequest instance is a writable stream. If one needs to upload a file with a POST request, then write to the ClientRequest object."

So execution returns immediately from the https.request() call, without waiting for anything. On this request object, an error handler is installed, then the request is finished (and flushed) by calling .end() since we don't want to send a body.

Then the new Promise executor callback concludes, the new promise is returned somewhere, and usually the code that made the call will await it or call .then() to install fulfillment/rejection handlers on the promise.

Only after all this happened, at some later point in time, the response or error events will occur.

  • Related