成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

走近Node.js的異步代碼設計

譯文
開發 前端
許多企業目前在評估Node.js的異步、事件驅動型的I/O,認為這是一種高性能方案,可以替代多線程企業應用服務器的傳統同步I/O。異步性質意味著,企業開發人員必須學習新的編程模式,忘掉舊的編程模式。他們必須徹底轉變思路,可能需要借助電擊療法^_^。本文介紹了如何將舊的同步編程模式換成全新的異步編程模式。

【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()回調里面。

#p#

并行處理

異步代碼特別適合操作I/O操作的并行處理:代碼的執行并不因I/O調用的返回而受阻。多個I/O操作可以并行開始。在下面示例中,某個目錄中所有文件的大小都在循環中累加,以獲得那些文件占用的總字節數。使用異步代碼,循環的每次迭代都必須等到獲取單個文件大小的I/O調用返回為止。

異步代碼允許快速連續地在循環中開始所有I/O調用,不用等結果返回。只要其中一個I/O操作完成,回調函數就被調用,而該文件的大小就可以添加到總字節數中。

唯一必不可少的有一個恰當的停止標準,它決定著我們完成處理后,就計算所有文件的總字節數。

同步

  1. var fs = require('fs');  
  2. function calculateByteSize() {  
  3.     var totalBytes = 0,  
  4.         i,  
  5.         filenames,  
  6.         stats;  
  7.     filenames = fs.readdirSync(".");  
  8.     for (i = 0; i < filenames.length; i ++) {  
  9.         stats = fs.statSync("./" + filenames[i]);  
  10.         totalBytes += stats.size;  
  11.     }  
  12.     console.log(totalBytes);  
  13. }  
  14.  
  15.  
  16.  
  17. calculateByteSize(); 

異步

  1. var fs = require('fs');  
  2. var count = 0,  
  3.     totalBytes = 0;  
  4. function calculateByteSize() {  
  5.     fs.readdir(".", function (err, filenames) {  
  6.         var i;  
  7.         count = filenames.length;  
  8.         for (i = 0; i < filenames.length; i++) {  
  9.             fs.stat("./" + filenames[i], function (err, stats) {  
  10.                 totalBytes += stats.size;  
  11.                 count--;  
  12.                 if (count === 0) {  
  13.                     console.log(totalBytes);  
  14.                 }  
  15.             });  
  16.         }  
  17.     });  
  18. }  
  19. calculateByteSize(); 

同步示例簡單又直觀。在異步版本中,***個fs.readdir()被調用,以讀取目錄中的文件名稱。在回調函數中,針對每個文件調用fs.stat(),返回該文件的統計信息。這部分不出所料。

值得關注的方面出現在計算總字節數的fs.stat()回調函數中。所用的停止標準是目錄的文件數量。變量count以文件數量來初始化,倒計數回調函數執行的次數。一旦數量為0,所有I/O操作都被回調,所有文件的總字節數被計算出來。計算完畢后,字節數可以記錄到控制臺。

異步示例有另一個值得關注的特性:它使用閉包(closure)。閉包是函數里面的函數,內層函數訪問外層函數中聲明的變量,即便在外層函數已完成之后。fs.stat()回調函數是閉包,因為它早在fs.readdir()回調函數完成后,訪問在該函數中聲明的count和totalBytes這兩個變量。閉包有關于它自己的上下文。在該上下文中,可以放置在函數中訪問的變量。

要是沒有閉包,count和totalBytes這兩個變量都必須是全局變量。這是由于fs.stat()回調函數沒有放置變量的任何上下文。calculateBiteSize()函數早已結束,只有全局上下文仍在那里。這時候閉包就能派得上用場。變量可以放在該上下文中,那樣可以從函數里面訪問它們。

代碼復用

代碼片段可以在JavaScript中復用,只要把代碼片段包在函數里面。然后,可以從程序中的不同位置調用這些函數。如果函數中使用了I/O操作,那么改成異步代碼時,就需要某種重構。

下面的異步示例顯示了返回某個目錄中文件數量的函數countFiles()。countFiles()使用I/O操作fs.readdirSync() 來確定文件數量。span style="font-family: courier new,courier;">countFiles()本身被調用,使用兩個不同的輸入參數:

同步

  1. var fs = require('fs');  
  2. var path1 = "./",  
  3.     path2 = ".././";  
  4. function countFiles(path) {  
  5.     var filenames = fs.readdirSync(path);  
  6.     return filenames.length;  
  7. }  
  8. console.log(countFiles(path1) + " files in " + path1);  
  9. console.log(countFiles(path2) + " files in " + path2); 

異步

  1. var fs = require('fs');  
  2. var path1 = "./",  
  3.     path2 = ".././",  
  4.     logCount;  
  5. function countFiles(path, callback) {  
  6.     fs.readdir(path, function (err, filenames) {  
  7.         callback(err, path, filenames.length);  
  8.     });  
  9. }  
  10. logCount = function (err, path, count) {  
  11.     console.log(count + " files in " + path);  
  12. };  
  13. countFiles(path1, logCount);   
  14. countFiles(path2, logCount);  

把fs.readdirSync()換成異步fs.readdir()迫使閉包函數cntFiles()也變成異步,因為調用cntFiles()的代碼依賴該函數的結果。畢竟,只有fs.readdir()返回后,結果才會出現。這導致了cntFiles()重構,以便還能接受回調函數。整個控制流程突然倒過來了:不是console.log()調用cntFiles(),cntFiles()再調用fs.readdirSync(),在異步示例中,而是cntFiles()調用fs.readdir(),然后cntFiles()再調用console.log()。

結束語

本文著重介紹了異步編程的一些基本模式。將思路轉變到異步編程絕非易事,需要一段時間來適應。雖然難度增加了,但是獲得的回報是顯著提高了并發性。結合JavaScript的快速周轉和易于使用等優點,Node.js中的異步編程有望在企業應用市場取得進展,尤其是在新一代高度并發性的Web 2.0應用程序方面。

原文:http://shinetech.com/thoughts/thought-articles/139-asynchronous-code-design-with-nodejs
 

【編輯推薦】

  1. 使用Node.js開發多人玩的HTML 5游戲
  2. Node.js提速指南
  3. Node.js專區
  4. 什么是Node.js?
  5. 使用node.js進行服務器端JavaScript編程
責任編輯:陳貽新 來源: 51CTO
相關推薦

2021-04-06 10:15:29

Node.jsHooks前端

2025-01-13 00:00:00

2021-03-04 23:12:57

Node.js異步迭代器開發

2021-03-16 16:16:41

GeneratorWebsockets前端

2012-02-02 15:14:29

Node.js

2020-12-08 06:28:47

Node.js異步迭代器

2021-01-26 08:07:44

Node.js模塊 Async

2013-11-01 09:34:56

Node.js技術

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2022-04-02 06:04:03

Node.js代碼緩存V8

2012-01-10 10:04:43

Node.js

2021-12-25 22:29:57

Node.js 微任務處理事件循環

2012-02-03 09:25:39

Node.js

2020-05-29 15:33:28

Node.js框架JavaScript

2021-10-22 08:29:14

JavaScript事件循環

2021-09-07 07:53:43

工具

2011-09-08 13:46:14

node.js

2011-11-01 10:30:36

Node.js

2011-09-02 14:47:48

Node

2011-09-09 14:23:13

Node.js
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕av中文字幕 | 亚洲在线电影 | 国产一区精品 | 精品欧美乱码久久久久久1区2区 | 精品国产aⅴ | 国产一在线观看 | 一区二区三区四区在线视频 | 在线观看av网站永久 | 日韩视频在线免费观看 | 久久天堂 | 精品国产乱码久久久久久蜜柚 | 精品一级| 久久亚洲一区 | 精品无码久久久久国产 | 亚洲嫩草 | 欧美视频在线播放 | 精品一区二区三区电影 | 一区二区精品 | 伊人最新网址 | 黄免费在线 | 久久久激情视频 | 天天夜碰日日摸日日澡 | 黄色片在线网站 | 国产综合精品一区二区三区 | 欧美国产日韩在线观看 | 日日操日日干 | 婷婷精品 | 久精品视频 | 一区二区免费 | 91精品国产综合久久精品图片 | 黄色一级毛片 | 欧美中文字幕在线观看 | 九色 在线| 日本a在线 | 国产精品精品 | 精品久久久久久久久久久久久久 | 三级视频网站 | 亚洲电影第三页 | 91久久久久久久久久久久久 | 黄色毛片在线观看 | 中文字幕av一区二区三区 |