ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • The Internals of Node.js
    Framework/Node.js 2020. 2. 21. 14:33

    1. Overview

    Node.js is an open-source, cross-platform, JavaScript library that executes JavaScript code outside of a browser. Node.js lets developers use JavaScript to write command-line tools and for server-side scripting—running scripts server-side to produce dynamic web page content before the page is sent to the user's web browser. Consequently, Node.js represents a "JavaScript everywhere" paradigm, unifying web application development around a single programming language, rather than different languages for server- and client-side scripts.

    2. Description

    2.1 Intuition

    You want to write a javascript code and just have it work. So that's one of the purposes of node.js. Node gives us a nice interface to use to relate our javascript side of our application to the actual C++ that's running on our computer to actually interpret and execute our Javascript code.

    So for example node implements the HTTP module and FS path crypto all these modules right here have very consistent API. And they all ultimately refer to a functionality that is mostly implemented inside of the lib project over here.

    2.2 Module Implementation

    V8 is used to interpret and execute Javascript code, while libuv is used for accessing the filesystem and some aspects of concurrency

    3. Event Loop

    3.1 Process and Threads

    3.2 The Node Event Loop

    This event loop is the absolute core of every program that you and I run and every program that you and I run has exactly one event loop. Understanding how the event loop works are extremely important because a lot of performance concerns about node boiled down to eventually how the event loop behaves.

    3.2.1 Pseudo code of Event Loop

    Pseudo Code of Event Loop of Node.js
    
    const pendingTimers = [];
    const pendingOSTasks = [];
    const pendingOperations = [];
    
    function shouldContinue() {
    	// Check any pending setTimeout, setInterval, setImmediate
    	// Check any pending OS tasks like server listening to port)
    	// Check any pending long-running operations like fs module
    	return pendingTimers.length || pendingOSTasks.length || pendingOperations.length
    }
    
    // Entire body execute
    while(shouldContinue()) {
    
    // 1) Node looks at pendingTimers and sees if any functions are ready to be called
    // setTimeout, setInterval
    
    // 2) Node looks at pendingOSTasks and pendingOperations and calls relevant callbacks
    
    // 3) Pause execution. Continue when...
    // - a new pendingOSTask is done
    // - a new pendingOperation is done
    // - a timer is about to complete
    
    // 4) Look at pendingTimers. Call any setImmediate
    
    // 5) Handle any 'close' events
    
    }

    3.2.2 Single Thread or not

    3.2.3 Thread example 1

    const crypto = require('crypto');
    
    
    // The instant we execute this file they are both executed at the same exact time.
    // The second thing to be aware of here is that we are not modifying the start variable at all.
    const start = Date.now();
    crypto.pbkdf2('a', 'b', 100000, 512, 'sha512', () => {
        console.log('1:', Date.now() - start);
    });
    
    crypto.pbkdf2('a', 'b', 100000, 512, 'sha512', () => {
        console.log('2:', Date.now() - start);
    });
    
    // output of only one revoking pbkdf2
    1: 473
    
    // output of two revoking pbkdf2
    // anyways the point is that chances are we're going to see two times or two benchmarks that are extremely
    // close in time to the original one.
    D:\nodejs>node threads.js
    1: 455
    2: 461
    

    3.2.4 Thread example 2

    const https = require('https')
    
    const start = Date.now()
    
    function doRequest() {
        https.request('https://www.google.com', res => {
            res.on('data', () => {
            });
            res.on('end', () => {
                console.log(Date.now() - start);
            });
        }).end();
    }
    
    doRequest();
    doRequest();
    doRequest();
    doRequest();
    doRequest();
    doRequest();
    doRequest();
    
    // output
    // This is distinctly different behavior than what we saw previously with our thread pool.
    // So remember by default the thread pool has four threads 
    // which means only four task can be processed
    // at a time.
    // But in this case we had six tasks all completed simultaneously.
    D:\nodejs>node async.js
    336
    381
    413
    421
    451
    452
    552
    

    because libuv is delegating the work done to the operating system itself decides whether to make a new thread or not. Or just generally how to handle the entire process of making the request. So because the operating system is making the request there is no blocking of our javascript code inside of our event loop or anything else inside of our application. Everything or all the work is being done by the operating system itself and we're not touching a thread pool at all in this case.

    3. Reference

    https://heynode.com/tutorial/how-event-loop-works-nodejs

    https://en.wikipedia.org/wiki/Node.js

    https://github.com/nodejs/node

    'Framework > Node.js' 카테고리의 다른 글

    Data Caching with Redis  (0) 2020.02.22
    Enhancing Node Performance  (0) 2020.02.21
    Single Thread, Event Loop, and Blocking Code  (0) 2020.02.21

    댓글

Designed by Tistory.