Event driven programming in node. js

  • 2020-03-30 03:42:43
  • OfStack

In traditional programming mode, an I/O operation is like a normal local function call: the program is blocked and cannot continue until the function is finished. Blocking I/O originated in the early time slice model, in which each process acted like a separate person to distinguish each person, and each person could usually only do one thing at a time and had to wait for the previous thing to finish before deciding what to do next. But this "one user, one process" model, which is widely used on computer networks and the Internet, scales poorly. Managing multiple processes consumes a lot of memory and context switching takes up a lot of resources, which is a big burden on the operating system, and can lead to a dramatic decline in system performance as the number of processes increases.

Multithreading is an alternative, a thread is a lightweight process, it will share with other threads within the same process of memory, it is more like an extension of the traditional model, used for concurrent execution of multiple threads, when a thread is waiting for I/O operations, other threads can control of the CPU when the I/O operation is completed, in front of the waiting thread will be awakened. That is, a running thread can be interrupted and later resumed. In addition, on some systems threads can run in parallel on different cores of multi-core cpus.

Programmers do not know exactly when a thread will run, and they must be careful to handle concurrent access to Shared memory, so they must use synchronization primitives to synchronize access to a data structure, such as locks or semaphores, to force the thread to perform a specific behavior and schedule. For applications that rely heavily on Shared state between threads, it's easy to have some strange problems that are too random to find.

Another way is to use multithreading collaboration, by your own responsible for the release of the explicit CPU, and the CPU time to other threads, because by you personally to control the threads of execution plan, reducing the need for synchronization, but also increase the complexity of the program and the chance of error, and did not avoid multithreading of those problems.

What is event-driven programming

Event-driven programming (Evnet - driven programming) is a programming style, by the event to determine the execution process and events from the event handler (event handler) or event callback, the event callback), event callback is invoked when a particular event occurs functions, such as a database to return the query results or the user clicks a button.

Recall that in traditional clogging I/O programming mode, a database query might look like this:


result = query('SELECT * FROM posts WHERE id = 1'); do_something_with(result);

The query function above leaves the current thread or process in a waiting state until the underlying database completes the query and returns.

In the event-driven model, the query would look like this:


query_finished = function(result) {         do_something_with(result); } query('SELECT * FROM posts WHERE id = 1', query_finished);

    First you define a function called query_finished, which contains what to do after the query completes. This function is then passed to the query function as an argument, and query_finished is called when query execution is complete, rather than simply returning the query result.

The programming model is called event-driven or asynchronous programming, which calls the function you defined when the event you're interested in occurs, rather than simply returning the result value. This is one of the most obvious features of Node. This programming model means that the current process cannot be blocked while performing an I/O operation, so multiple I/O operations can be executed in parallel, and the corresponding callback function is called when the operation is completed.

The underlying event-driven programming relies on an event loop, which is basically a structure that loop calls event detection and event handler trigger. In each loop, the event loop mechanism needs to detect which events are occurring, and when they occur, it finds the corresponding callback function and calls it.

The event loop is just a thread running in the process. When an event occurs, the event handler can run independently without being interrupted.

At most one event callback function runs at any given time
2. No event handler is interrupted while running

With this, developers can stop worrying about thread synchronization and concurrent changes to Shared memory.

A well-known secret:

The system programming community has known for a long time that event-driven programming is the best way to create highly concurrent services because it saves a lot of memory, less context switching, and a lot of execution time.

Over time, this concept spread to other platforms and communities, with the emergence of well-known Event loop implementations such as Ruby's Event machine,Perl's AnyEvnet, and Python's Twisted, among many other implementations and languages.

To develop with these frameworks, you need to learn frame-specific knowledge and frame-specific libraries. For example, when using Event Machine, in order to enjoy the benefits of non-blocking, you should avoid using synchronous libraries and only use asynchronous libraries of Event Machine. If you use any blocking libraries (like most of Ruby's standard libraries), you lose the best scalability of your server because the event loop is still constantly blocked, blocking the processing of I/O events from time to time.

Node was originally designed as a non-blocking I/O server platform, so in general, you should expect all the code running on it to be non-blocking. Because JavaScript is so small, and it doesn't enforce any I/O model (because it doesn't have a standard I/O library), Node is built in a very clean environment with no legacy issues.

How does Node and JavaScript simplify asynchronous applications

Ryan Dahl, the author of Node, originally developed the project using C, but found that maintaining the context for function calls was too complex, resulting in high code complexity. He then switched to Lua, but Lua already had several blocked I/O libraries, and the mix of blocking and non-blocking might confuse developers and thus discourage many from building scalable applications, so Lua was abandoned by Dahl. Finally he turned to JavaScript, closures in JavaScript, and functions for first-class objects, features that make JavaScript ideal for event-driven programming. The magic of JavaScript is one of the main reasons Node is so popular.

What is a closure

A closure can be thought of as a special function, but it can inherit and access variables in the scope in which it is defined. When you pass a callback function as an argument to another function, it is called later, and the magic is that when the callback function is called later, it remembers the context in which it defines itself and the variables in the parent context, and it has normal access to them. This powerful feature is at the heart of Node's success.

The following example shows how JavaScript closures work in a Web browser. If you want to listen for a button's stand-alone event, you can do this:


var clickCount = 0; document.getElementById('myButton').onclick = function() {         clickCount += 1;         alert("clicked " + clickCount + " times."); };

Here's how to use jQuery:


var clickCount = 0; $('button#mybutton').click(function() {         clickedCount ++;         alert('Clicked ' + clickCount + ' times.'); });

In JavaScript, functions are the first type of object, which means you can pass functions as arguments to other functions. The above two examples, the former put a function assigned to another function, the latter the function passed as a parameter to another function, the click event handler (callback function) can access the function is defined under the code block of each variable, in this case, it can access in its parent clickCount variable defined in the closure.

The clickCount variable is in the global scope (the outermost scope in JavaScript), and it stores the number of times the user clicks the button. It is often a bad habit to store variables in the global scope, because it can easily conflict with other code. You should place variables in the local scope where they are used. Most of the time, just wrapping the code in a single function creates another closure, which makes it easy to avoid polluting the global environment, like this:


                  (function() {                             var clickCount = 0;                             $('button#mybutton').click(function() {                                      clickCount ++;                                      alert('Clicked ' + clickCount + ' times.');                             });                    }());


  Note: in line 7 above, you define a function and call it immediately. This is a common design pattern in JavaScript: create a function to create a new scope.

How do closures help asynchronous programming

In the event-driven programming model, you write the code that will be run after the event has occurred, then you put the code into a function that is passed as an argument to the caller, which is then called by the caller function.

In JavaScript, a function is not an isolated definition; it also remembers the context of the scope in which it is declared. This mechanism allows JavaScript functions to access all variables in the context in which the function is defined and in the parent context.

When you pass a callback function as an argument to the caller, the function is called at a later time. Even if the scope in which the callback function is defined has ended, it can still access all variables in the closed scope and its parent scope when the callback function is called. As in the last example, the callback function is called inside jQuery's click(), but it still has access to the clickCount variable.

The magic of closures was shown earlier. Passing state variables to a function allows you to do event-driven programming without maintaining state, and JavaScript's closure mechanism helps you maintain them.

summary

Event-driven programming is a programming model that USES event triggers to determine the flow of program execution. Programmers register callback functions (commonly referred to as event handlers) for the events they are interested in, and then the system calls the registered event handlers when the event occurs. This programming model has many advantages that traditional blocking programming models do not, and previously you had to use multiple processes/threads to implement similar features.

JavaScript is a powerful language because its first-type object functions and closure features make it ideal for event-driven programming.


Related articles: