Process Control in Node. js (1)

Source: Internet
Author: User

The only challenge for programming in an asynchronous framework such as node is how to control which functions are executed in sequence and which functions are executed in parallel. Node does not have a built-in control method. Here I will share some of the skills used to compile the program on this site.

Parallel VS Sequence

Generally, some steps in an application can run only after the results of previous operations are obtained. This is easy to solve in normal sequential execution programs, because each part must wait until the execution of the previous part is completed.

In Node, this problem exists in other methods except for those that execute blocking IO. For example, scan folders, open files, read file content, and query databases.

For my blog engine, some files are organized in a tree structure and need to be processed. The procedure is as follows:

◆ Get the article list (the author's blog uses the file system to store the article list, starting with scanning folders ).

◆ Read and parse the article data.

◆ Obtain the author list.

◆ Read and parse the author's data.

◆ Get the HAML template list.

◆ Read all HAML templates.

◆ Obtain the resource file list.

◆ Read all resource files.

◆ Generate the article html page.

◆ Generate the author page.

◆ Create an index page ).

◆ Generate the feed page.

◆ Generate static resource files.

As you can see, some steps can be executed independently (but some cannot) without other steps ). For example, you can read all files at the same time, but you must scan the folder to obtain the file list. I can write all files at the same time, but I have to wait until the calculation of all the file content is complete before writing.

Use group counters

For the following example of scanning the cat folder and reading the files, we can use a simple counter:

 
 
  1. var fs = require('fs');  
  2.  
  3. fs.readdir(".", function (err, files) {  
  4.   var count = files.length,  
  5.       results = {};  
  6.   files.forEach(function (filename) {  
  7.     fs.readFile(filename, function (data) {  
  8.       results[filename] = data;  
  9.       count--;  
  10.       if (count <= 0) {  
  11.         // Do something once we know all the files are read.  
  12.       }  
  13.     });  
  14.   });  
  15. });  

Nested callback functions are a good way to ensure their sequential execution. Therefore, in the readdir callback function, we set a countdown counter based on the number of files. Then we execute the readfile operation on each file, which will be executed in parallel and completed in any order. The most important thing is that when each file is read, the counter value is reduced by 1. When the value of the counter is changed to 0, we know that all the files have been read.

Avoid excessive nesting by passing callback Functions

After obtaining the file content, we can perform other operations in the function at the innermost layer. However, when the number of sequential operations exceeds 7, this will soon become a problem.

Let's modify the above instance by passing the callback:

 
 
  1. var fs = require('fs');  
  2.  
  3. function read_directory(path, next) {  
  4.   fs.readdir(".", function (err, files) {  
  5.     var count = files.length,  
  6.         results = {};  
  7.     files.forEach(function (filename) {  
  8.       fs.readFile(filename, function (data) {  
  9.         results[filename] = data;  
  10.         count--;  
  11.         if (count <= 0) {  
  12.           next(results);  
  13.         }  
  14.       });  
  15.     });  
  16.   });  
  17. }  
  18.  
  19. function read_directories(paths, next) {  
  20.   var count = paths.length,  
  21.       data = {};  
  22.   paths.forEach(function (path) {  
  23.     read_directory(path, function (results) {  
  24.       data[path] = results;  
  25.       count--;  
  26.       if (count <= 0) {  
  27.         next(data);  
  28.       }  
  29.     });  
  30.   });  
  31. }  
  32.  
  33. read_directories(['articles', 'authors', 'skin'], function (data) {  
  34.   // Do something  
  35. });  

Now we have written a hybrid asynchronous function that receives some parameters (in this example, the path) and a callback function called after all the operations are completed. All operations will be completed in the callback function. The most important thing is to convert multi-layer nesting into a non-nested callback function.

Combo Library

I used my free time to write a simple Combo library. Basically, it encapsulates the process of counting events and calling the callback function after all events are completed. It also ensures that the callback functions are executed in the registered order regardless of the actual execution time.

 
 
  1. function Combo(callback) {  
  2.   this.callback = callback;  
  3.   this.items = 0;  
  4.   this.results = [];  
  5. }  
  6.  
  7. Combo.prototype = {  
  8.   add: function () {  
  9.     var self = this,  
  10.         id = this.items;  
  11.     this.items++;  
  12.     return function () {  
  13.       self.check(id, arguments);  
  14.     };  
  15.   },  
  16.   check: function (id, arguments) {  
  17.     this.results[id] = Array.prototype.slice.call(arguments);  
  18.     this.items--;  
  19.     if (this.items == 0) {  
  20.       this.callback.apply(this, this.results);  
  21.     }  
  22.   }  
  23. };  

If you want to read data from databases and files and perform some operations after completion, you can do the following:

 
 
  1. // Make a Combo object.  
  2. var both = new Combo(function (db_result, file_contents) {  
  3.   // Do something  
  4. });  
  5. // Fire off the database query  
  6. people.find({name: "Tim", age: 27}, both.add());  
  7. // Fire off the file read  
  8. fs.readFile('famous_quotes.txt', both.add());  

Database Query and file reading will start at the same time. When all of them are completed, the callback function passed to the combo constructor will be called. The first parameter is the database query result, and the second parameter is the file read result.

Conclusion

Tips described in this article:

◆ Obtain the behavior of sequential execution through nested callback.

◆ Obtain the behavior of parallel execution through direct function calls.

◆ Use the callback function to resolve the nesting caused by sequential operations.

◆ Use counters to check when a group of parallel operations are completed.

◆ Use libraries like combo to simplify operations.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.