senchalabs / connect

Connect is a middleware layer for Node.js
MIT License
9.84k stars 1.09k forks source link

defer function #1099

Closed islomkhodja closed 6 years ago

islomkhodja commented 6 years ago

Why we use the defer(), and not just the done()?

    // next callback
    var layer = stack[index++];

    // all done
    if (!layer) {
      defer(done, err);
      return;
    }

In which cases: -What happens if I just use the done()? -What is prevented when using the defer()?

Can you give examples?

dougwilson commented 6 years ago

This was implemented due to multiple reported issues. You can check out the original change, along with a test case in the commit: https://github.com/senchalabs/connect/commit/be0382481b684f6ef5893da0bb2247b0e177e488

The underlying reason is that in Node.js the callback is expected to call back on a future "tick" than the original call of the function for consistency. A generic example is take the following code:

console.log('1')

doSomething(function () {
   console.log('2')
})

console.log('3')

Given that code, the result should be consistent, as in it should always be either 1,3,2 or 1,2,3. It shoud not depend on different things within doSomething otherwise it's not possible to reason about the code execution flow. Before the change in connect, the order would depend on what was in the app, while after the change (through the defer function), it is _always 1,3,2 no matter what the app does and what the request is going to be.

The other issue had to do with errors within the callback itself. Since connect wraps handlers within a try / catch automatically in order to catch the error and forward it on, an error happning within the callback would end up bubbleing back into connect without the defer. This would usually end up calling the callback a second time, typicallying throwing again and the error would be swallowed. With the defer in place, a thrown error in the callback will cause an unhandled exception and will not (1) swallow the error and (2) invoke the callback multiple times.

I hope that helps!