Search code examples
node.jsasync-awaitnonblockingsingle-threaded

Can two piece of code be run at the same time in node.js?


As I understand the non-blocking concept this could happen. But the one threat architecture of node.js made me doubt about it.

Let's say I have two endpoints on my HTTP server:

app.get('/one', ()  => {
    global.counter = 'A'
    global.counter += 'A'
    global.counter += 'A'
    ...
})

app.get('/two', ()  => {
    global.counter = 'B'
    global.counter += 'B'
    global.counter += 'B'
    ...
})

What happen if the server receive two request almost at the same time. Can global.counter end up with a mix of A and B?

What about using async/await like global.counter += await getB()?


Solution

  • In your example global.counter can never end up with a mix of 'A' and 'B' because each function callback will be run after the previous one had already finished. The requests will be processed asynchronously but not in parallel since only one thread is running for user code.

    However, when you have asynchronous operations inside the callback function, e.g. network fetch, database access or a file read, the second user-made request might complete before the first one and thus alter the global state before the first function accesses it.

    let state;
    
    function timeout(ms) {
      return new Promise(resolve => {
        setTimeout(resolve, ms)
      })
    }
    
    async function req1() {
      state = 'A';
      await timeout(100);
      state += 'A';
      console.log(`Req 1: ${state}`);
    }
    
    async function req2() {
      state = 'B';
      await timeout(50);
      state += 'B';
      console.log(`Req 2: ${state}`);
    }
    
    req1();
    req2();
    
    // Prints:
    // "Req 2: BB"
    // "Req 1: BBA"
    

    This is one of the reasons why it's a bad idea to rely on global state in a HTTP server's request callbacks (e.g. Express or Koa).