What steps does Node.js takes to execute a program?

前端 未结 2 1728
臣服心动
臣服心动 2021-01-16 15:33

I\'m exploring node.js for quite some time now. But yet haven\'t figured out exactly, how a program executes.

For e.g. taking this simple program:

/         


        
2条回答
  •  南笙
    南笙 (楼主)
    2021-01-16 16:27

    Blocking I/O is just that: the call does not return until it has completed. So when you call readFileSync, it makes calls directly to the OS API to read in a file and only when the entire contents have been copied into a Buffer does control return to your JS.

    With blocking (synchronous) functions, the event loop has absolutely nothing to do with how the I/O is handled. This is why synchronous I/O is very bad in node – it prevents anything else from happening since the event loop is not running.

    On the other hand, the normal (asynchronous) I/O functions like readFile simply put in a request for I/O to be done and then return. Exactly how that I/O is performed depends on the nature of the I/O request (ie whether filesystem or network), but it is all handled by the C library libuv on a separate thread.

    • Network I/O is actually performed using the host OS's native asynchronous I/O facilities, which is very fast and does not necessitate a separate thread for each connection.

      Whenever the OS reports network I/O activity, the event is placed in a queue. On the next tick of the event loop, the event is picked up and dispatched to the appropriate JavaScript function. (C code can obtain a reference to JS functions and invoke them.)

    • File I/O is done using normal blocking system I/O calls. Each I/O request is placed in the libuv work queue and executed by a thread pool. The key here is that the blocking I/O is done in C, on a thread separate from the JavaScript thread.

      When the blocking I/O call returns, the result is placed in a queue. Again, the event is dispatched on the next tick.

    Node keeps a reference count of pending work requests – things like I/O, timers, and listening servers. If there are zero at the end of a tick, the process exits. (In some cases, you can explicitly remove an active request from the reference count with unref().)

    Some other related answers will help explain some of these concepts further:

    • What exactly is a node.js event loop tick?
    • Further discussion of I/O in node

    Finally, let's walk through your example program. Here's exactly what happens:

    • require('fs') gives you a reference to the already-initialized fs module. The builtin modules are special and do not require I/O to load.
    • fs.readFileSync calls in to the OS file APIs. It does not return until the file contents are copied into memory.
    • fs.readFile adds an item (containing the filename and a reference to the callback) to the libuv work queue, then returns immediately. (Because there would be nothing on the work queue, the I/O will begin shortly on a separate thread.)
    • The contents of fileBuffer are logged to the console.
    • At this point, control reaches the end of your program, so it goes back to node. This is the end of the very first tick. Since there is pending I/O, node does not exit.
    • node enters an "idle" state. The event loop checks the event queue for new items in an indefinite loop. Many ticks pass by until...
    • The asynchronous I/O operation finally completes and adds the result to the event queue. The next tick pops the event off the queue and invokes the callback function you initially passed to readFile.
    • The contents of data are logged to the console and the callback function returns.
    • The tick has ended, and there is no more pending work. Node exits.

提交回复
热议问题