走近Node.js的异步代码设计(1)


【51CTO精选译文】许多企业目前在评估Node.js的异步、事件驱动型的I/O,认为这是一种高性能方案,可以替代多线程企业应用服务器的传统同步I/O。异步性质意味着,企业开发人员必须学习新的编程模式,忘掉旧的编程模式。他们必须彻底转变思路,可能需要借助电击疗法^_^。本文介绍了如何将旧的同步编程模式换成全新的异步编程模式。


51CTO推荐专题:Node.js专区


开始转变思路


要使用Node.js,就有必要了解异步编程的工作原理。异步代码设计并非简单的设计,需要一番学习。现在需要来一番电击疗法:本文在同步代码示例旁边给出了异步代码示例,表明如何更改同步代码,才能变成异步代码。这些示例都围绕Node.js的文件系统(fs)模块,因为它是唯一含有同步I/O操作及异步I/O操作的模块。有了这两种示例,你可以开始转变思路了。


相关代码和独立代码


回调函数(callback function)是Node.js中异步事件驱动型编程的基本构建模块。它们是作为变量,传递给异步I/O操作的函数。一旦操作完成,回调函数就被调用。回调函数是Node.js中实现事件的机制。


下面显示的示例表明了如何将同步I/O操作转换成异步I/O操作,并显示了回调函数的使用。示例使用异步fs.readdirSync()调用,读取当前目录的文件名称,然后把文件名称记录到控制台,最后读取当前进程的进程编号(process id)。


同步


  1. var fs = require('fs'),  
  2.     filenames,  
  3.     i,  
  4.     processId;  
  5. filenames = fs.readdirSync(".");  
  6. for (i = 0; i < filenames.length; i++) {  
  7.     console.log(filenames[i]);  
  8. }  
  9. console.log("Ready.");  
  10. processprocessId = process.getuid();  

异步


  1. var fs = require('fs'),  
  2.     processId;  
  3. fs.readdir(".", function (err, filenames) {  
  4.     var i;  
  5.     for (i = 0; i < filenames.length; i++) {  
  6.         console.log(filenames[i]);  
  7.     }  
  8.     console.log("Ready.");  
  9. });  
  10. processprocessId = process.getuid(); 

在同步示例中,处理器等待fs.readdirSync() I/O操作,所以这是需要更改的操作。Node.js中该函数的异步版本是fs.readdir()。它与fs.readdirSync()一样,但是回调函数作为第二个参数。


使用回调函数模式的规则如下:把同步函数换成对应的异步函数,然后把原先在同步调用后执行的代码放在回调函数里面。回调函数中的代码与同步示例中的代码执行一模一样的操作。它把文件名称记录到控制台。它在异步I/O操作返回之后执行。


就像文件名称的记录依赖fs.readdirSync() I/O操作的结果,所列文件数量的记录也依赖其结果。进程编号的存储独立于I/O操作的结果。因而,必须把它们移到异步代码中的不同位置。


规则就是将相关代码移到回调函数中,而独立代码的位置不用管。一旦I/O操作完成,相关代码就被执行,而独立代码在I/O操作被调用之后立即执行。


顺序


同步代码中的标准模式是线性顺序:几行代码都必须下一行接上一行来执行,因为每一行代码依赖上一行代码的结果。在下面示例中,代码首先变更了文件的访问模式(比如Unix chmod命令),对文件更名,然后检查更名后文件是不是符号链接。很显然,该代码无法乱序运行,不然文件在模式变更前就被更名了,或者符号链接检查在文件被更名前就执行了。这两种情况都会导致出错。因而,顺序必须予以保留。


同步


  1. var fs = require('fs'),  
  2.     oldFilename,  
  3.     newFilename,  
  4.     isSymLink;  
  5. oldFilename = "./processId.txt";  
  6. newFilename = "./processIdOld.txt";  
  7. fs.chmodSync(oldFilename, 777);  
  8. fs.renameSync(oldFilename, newFilename);  
  9. isSymLink = fs.lstatSync(newFilename).isSymbolicLink(); 

异步


  1. var fs = require('fs'),  
  2.     oldFilename,  
  3.     newFilename;  
  4. oldFilename = "./processId.txt";  
  5. newFilename = "./processIdOld.txt";  
  6. fs.chmod(oldFilename, 777, function (err) {     
  7.     fs.rename(oldFilename, newFilename, function (err) {  
  8.         fs.lstat(newFilename, function (err, stats) {  
  9.             var isSymLink = stats.isSymbolicLink();  
  10.         });  
  11.     });  
  12. });  

在异步代码中,这些顺序变成了嵌套回调。该示例显示了fs.lstat()回调嵌套在fs.rename()回调里面,而fs.rename()回调嵌套在fs.chmod()回调里面。





标签:

友情链接
轻松育儿世界奇观
苏ICP备16066217号-2