11. Node. js asynchronous Process Control (sequential mode, concurrency mode, and limited concurrency Mode)
In terms of basic syntax, Javascript is no different from most other C-derived languages. You may easily go from other languages to Javascript. Many users who transfer from other languages to Javascript may love and hate this language after a while, especially for asynchronous process control.
Most asynchronous programming models are event-driven and process-based. This has brought us a lot of benefits. We don't have to deal with the problems in the multi-threaded model for the same purpose. In multi-thread programming, because multiple threads access the same memory block, there may be deadlocks, sharing competition, and other issues.
What is asynchronous programming? For example, you need to prepare a variety of dinners, including cooking and soup. For blocking Synchronous Programming, You need to stir-fry the dishes first, and then stir-fry the dishes. You cannot do other things during the cooking process. You can start your dinner only when both of them are ready. What Will asynchronous processing do? You can cook soup while cooking. When the food is fried, the soup may be good. Then you can start it. If the time of each step is used for calculation, the time cost of the two is obviously more to be done asynchronously.
Blocking Synchronous Programming: cooking (5 minutes) + cooking (30 minutes) = It took 35 minutes
Asynchronous programming model: [cooking (5 minutes) cooking (30 minutes)] = It took 30 minutes to cook
The above example shows that the asynchronous programming model is much more efficient than full task time and time utilization.
Significance of asynchronous stream processing
Asynchronous process control is not good, and it is easy to write Nested-style code. As the project goes deeper and functions expand, it will become increasingly difficult to maintain, perhaps this is one of the reasons why many programmers who are not used to JS do not like JS.
Async1 (function (input, result1 ){
Async2 (function (result2 ){
Async3 (function (result3 ){
Async4 (function (result4 ){
Async5 (function (output) {// do something with output });
});
});
});
})
The above code is the code we can see in some programmers, especially the code that is often prone to operation in the database. A previous colleague said that he didn't want to develop the program again after he used Node. js to develop the program once, because he had enough of the hard-to-maintain code. At that time, I recommended some process control libraries, such as Asyncjs and Step, to him. It is not clear whether the project is used.
Nested code may cause problems
Solution
Currently, the Community has three perspectives:
(1)
Separate the code. Although there are still problems with callback functions, the complexity of the Code is reduced. For example (nodejs is used as an example, but asynchronous process control is not a NODEJS patent ):
Var http = require ('http ');
Http. createServer (function (request, response ){
Response. writeHead (200, {'content-type': 'text/plain '});
Response. write ('hello ');
Response. end ();
}). Listen (80, '192. 0.0.1 ');
The above Code seems to have no problem, but if I want to return a file to the browser at this time, and if the file does not exist, 404 will be returned. If I want to add the database access function. If the code is all put in this. What will happen after maintenance!
Var http = require ('http ');
Function requesthander (req, res ){
Res. writeHead (200, {'content', 'text/plain '});
Res. wirte ('hello ');
Res. end ();
}
Http. createServer (requesthander). listen (80, '2017. 0.0.1 ');
This separation method was used by some early design institutes. The main idea is to flatten the nest code and separate the logic of each step. But this also brings about another problem. Although shared, code is too loose and the relationship between codes must be understood in depth.
(2)
Further abstracts the code and uses a Unified Library or toolkit to organize the code without disrupting the logic and organization of the original code. Many excellent libraries have emerged in the Javascript world. Libraries such as Setp and Async (such as Netease's open-source game development framework) provide rich stream control interfaces, with these interface methods, you can organize or use your code well to reduce the development burden.
The usage is as follows:
Async. series (
[
Function (callback ){
Callback (null, 'node. js'); // The execution result of the first function is passed to the next function.
},
Function (callback ){
Callback (null, 'javascript '); // The execution result of the second function is passed to the final callback function.
},
],
Function (err, response ){
// Response is ['node. js', 'javascript.
}
);
3)
Compile and execute. Yes, the general idea is to compile the existing code in some way to implement the asynchronous function. For example, Lao Zhao's Jscex in China. Although I do not like this style, I would like to give you a brief introduction to its code style. The use of Eval and the Code Organization make me discard using this library.
Next, we will start to discuss the three common js asynchronous process control modes in the community.
No matter how the code on the network changes, what interfaces are provided, but currently the following three modes are still inseparable. I hope that you can write your own asynchronous process control library or understand its basic principles through a simple introduction.
Series (serial mode)
------- Only one task is executed at a time.
Fully parallel (full concurrency Mode)
------- Execute all at once
Limitedly parallel (limits the concurrency Mode)
------- Execute concurrent tasks at a limited number each time.
Functions required by the asynchronous processing Library
1. provides methods to control the execution of function sets.
2. Data generated during execution can be collected.
3. Provide concurrency restrictions under special circumstances, because in some cases there is a limit on the number of concurrency, otherwise your system may be overwhelmed.
4. provides methods for execution after all function sets confirm that the execution is successful.
SeriesMode
Applicable scenarios: scenarios with specific requirements on execution sequence.
If multiple databases are queried and database statements are dependent on each other
For example, writing a file (directory permission, whether the file exists, and file permission );
Features:
Function set execution in sequence
Only one task is run at a time.
Make sure that the task is executed after the previous task is completed.
Data in each step is controllable and can be called (data sequence) when the next task is executed ).
Fully parallelMode
Applicable scenario: run multiple tasks concurrently. When all tasks have finished running the notification callback method. For example, multiple I/O operations
This mode may be required when the duration is not determined.
Features:
Run multiple tasks concurrently without waiting for the execution of the previous task to complete.
The operation execution can only be obtained in the callback function, because the execution sequence cannot be ensured in the concurrency mode.
Limited parallelMode
Applicable scenarios: The system resources are limited, and each execution task consumes more resources.
Features:
You can run multiple limited tasks concurrently without waiting for the execution of the previous task to complete.
The operation execution result can only be obtained in the callback function, because the execution sequence cannot be ensured in the concurrency mode.
Code with three modes :,
/**
* Series flow
* @ Param {Array} callbacks
* @ Param {Function} last
* @ Example series ([fun1 (next ){
SomeFun ();
Next (); // or next (value)
}, Fun2 (next ){
SomeFun ();
Next (); // or next (value)
}])
**/
Function series (callbacks, last ){
Var results = [];
Function next (){
Var callback = callbacks. shift ();
If (callback ){
Callback (function (){
Results. push (Array. prototype. slice. call (arguments ));
Next ();
});
} Else {
Last (results );
}
}
Next ();
}
// Example task
Function async (arg, callback ){
Var delay = Math. floor (Math. random () * 5 + 1) * 100; // random MS
Console. log ('async' with \ ''+ arg + '\', return in '+ delay + 'ms ');
SetTimeout (function () {callback (arg * 2) ;}, delay );
}
Function final (results) {console. log ('done', results );}
Series ([
Function (next) {async (1, next );},
Function (next) {async (2, next );},
Function (next) {async (3, next );},
Function (next) {async (4, next );},
Function (next) {async (5, next );},
Function (next) {async (6, next );}
], Final );
--------------------------------------------------------
Function fullParallel (callbacks, last ){
Var results = [];
Var result_count = 0;
Callbacks. forEach (function (callback, index ){
Callback (function (){
Results [index] = Array. prototype. slice. call (arguments );
Result_count ++;
If (result_count = callbacks. length ){
Last (results );
}
});
});
}
// Example task
Function async (arg, callback ){
Var delay = Math. floor (Math. random () * 5 + 1) * 100; // random MS
// Console. log ('asyncwith \ ''+ arg + '\', return in '+ delay + 'ms ');
For (var I = 0; I <100000000; I ++ ){
}
SetTimeout (function () {callback (arg * 2) ;}, delay );
Console. log (+ new Date ());
}
Function final (results) {console. log ('done', results );}
FullParallel ([
Function (next) {async (1, next );},
Function (next) {async (2, next );},
Function (next) {async (3, next );},
Function (next) {async (4, next );},
Function (next) {async (5, next );},
Function (next) {async (6, next );}
], Final );
-------------------------------------------------
Function limited (limit, callbacks, last ){
Var results = [];
Var running = 1;
Var task = 0;
Function next (){
Running --;
If (task = callbacks. length & running = 0 ){
Last (results );
}
While (running <limit & callbacks [task]) {
Var callback = callbacks [task];
(Function (index ){
Callback (function (){
Results [index] = Array. prototype. slice. call (arguments );
Next ();
});
}) (Task );
Task ++;
Running ++;
}
}
Next ();
}
// Example task
Function async (arg, callback ){
Var delay = Math. floor (Math. random () * 5 + 1) * 1000; // random MS
Console. log ('async' with \ ''+ arg + '\', return in '+ delay + 'ms ');
SetTimeout (function (){
Var result = arg * 2;
Console. log ('Return with \ ''+ arg + '\', result' + result );
Callback (result );
}, Delay );
}
Function final (results) {console. log ('done', results );}
Limited (2 ,[
Function (next) {async (1, next );},
Function (next) {async (2, next );},
Function (next) {async (3, next );},
Function (next) {async (4, next );},
Function (next) {async (5, next );},
Function (next) {async (6, next );}
], Final );
---------------------------------------------
References: http://book.mixu.net/
========================================================== ==========