-1

I'm new in Node, so the following code behavior is not clear to me:

function step(iteration) {
  if (iteration === 10) return;

  process.nextTick(() => {
    step(iteration + 1); // Recursive call from nextTick handler.
    console.log(`nextTick iteration: ${iteration}`);    
  });

  http.request({hostname: '127.0.0.1', port: 5000}, (response) => {
    console.log("here !");
  }).end();

  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);    
  });
}
step(0);

OUTPUT:

nextTick iteration: 0
...
nextTick iteration: 9
setImmediate iteration: 0
...
setImmediate iteration: 9
here !
here !
here !
here !
here !
here !
here !
here !
here !
here !

Questions are:

1) why http.request() callback is triggered after setImmediate()? I undestand, why setImmediate() is generally called: its callbacks were registered during the loop. But as documentation says, setImmediate() is a check phase, which should be processed in event loop after poll one. If I understood correctly, http.request() after nextTick() should be that poll phase;

2) but if http.request() is not handled in poll, in what phase does it happen? Especially considering that it works after setImmediate().

My Node.js version is 6.11.2. Thanks in advance for explanation.

Boolean_Type
  • 1,146
  • 3
  • 13
  • 40

1 Answers1

-1

To answer your questions:

  1. http.request() is called before setImmediate(). However, http.request is asynchronous. In your case, the callback is not run until after the request resolves. This means that although it is called first, the callback does not log anything until a later point in time—and that point is after the setImmediate() has resolved.
  2. Even though setImmediate queues its callbacks for execution in the order they are queued, they still are able to resolve before the request returns.

In order to handle your steps in order, consider moving the contents of the nextTick to within the callback for the request:

function step(iteration) {
  if (iteration === 10) return;

  http.request({hostname: '127.0.0.1', port: 8000}, (response) => {
    console.log("here !");

    step(iteration + 1); // Recursive call from nextTick handler.

    console.log(`nextTick iteration: ${iteration}`);    
  }).end();

  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);    
  });
}
step(0);

In that snippet, I've removed the nextTick, although you can safely add it in to the callback if needed.

Hans
  • 968
  • 7
  • 16
  • _although `http.request()` is called first, the callback does not log anything until a later point in time—and that point is after the `setImmediate()` has resolved._ - can you give a link on docs, please? – Boolean_Type Aug 25 '17 at 09:02
  • Because I've read [the opposite](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#poll): _If the poll queue_ (I assume, `http.request()` is in that queue) _is not empty, the event loop will iterate through its queue of callbacks executing them synchronously ... If scripts have been scheduled by setImmediate(), the event loop will end the poll phase and continue to the check phase to execute those scheduled scripts._ Therefore, I suggested that callback for request will trigger earlier, that `setImmediate`'s one. – Boolean_Type Aug 25 '17 at 09:02
  • The documentation you link to is correct, but it doesn't apply to the callback passed to `.request()`. Under https://nodejs.org/api/http.html#http_http_request_options_callback, it notes: "The optional callback parameter will be added as a one time listener for the 'response' event." Even through `.request()` is being executed immediately, the response is asynchronously received. You can see this if you listen for an immediate callback on the `request`, like `request.on('socket', ...)`, which appears to be synchronous, and logs before `setImmediate`. – Hans Aug 29 '17 at 21:40